Compare commits
12 changed files with 602 additions and 1172 deletions
|
|
@ -1,36 +0,0 @@
|
||||||
name: CI/CD Go Verification
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ main, dev ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ main ]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build_and_test:
|
|
||||||
runs-on: node20
|
|
||||||
steps:
|
|
||||||
- name: Checkout Code
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Go
|
|
||||||
uses: actions/setup-go@v5
|
|
||||||
with:
|
|
||||||
go-version: '1.25'
|
|
||||||
cache: true
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: go mod download
|
|
||||||
|
|
||||||
- name: Check code formatting
|
|
||||||
run: |
|
|
||||||
if [ -n "$(gofmt -l .)" ]; then
|
|
||||||
echo "Code is not formatted correctly. Run 'gofmt -w .'"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Build Application
|
|
||||||
run: go build -v ./...
|
|
||||||
|
|
||||||
- name: Run Tests (with Mocked Boundaries)
|
|
||||||
run: go test -v -cover ./...
|
|
||||||
61
go.mod
61
go.mod
|
|
@ -4,15 +4,12 @@ go 1.25.4
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bluesky-social/indigo v0.0.0-20251009224519-09f107c1109e
|
github.com/bluesky-social/indigo v0.0.0-20251009224519-09f107c1109e
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
|
||||||
github.com/google/jsonschema-go v0.4.3
|
|
||||||
github.com/joho/godotenv v1.5.1
|
github.com/joho/godotenv v1.5.1
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.9
|
||||||
|
github.com/mark3labs/mcp-go v0.43.2
|
||||||
github.com/mark3labs/x402-go v0.12.1
|
github.com/mark3labs/x402-go v0.12.1
|
||||||
github.com/modelcontextprotocol/go-sdk v1.6.1
|
github.com/nacorid/logger v0.0.0-20251221003040-586da7a03fa0
|
||||||
github.com/nacorid/logger v0.0.0-20251221013547-5fc8fd94ed80
|
|
||||||
github.com/ollama/ollama v0.12.10
|
github.com/ollama/ollama v0.12.10
|
||||||
github.com/x402-foundation/x402/go/v2 v2.19.0
|
|
||||||
golang.org/x/time v0.14.0
|
golang.org/x/time v0.14.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -20,54 +17,59 @@ require (
|
||||||
filippo.io/edwards25519 v1.1.0 // indirect
|
filippo.io/edwards25519 v1.1.0 // indirect
|
||||||
github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect
|
github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e // indirect
|
||||||
github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect
|
github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec // indirect
|
||||||
|
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||||
github.com/benbjohnson/clock v1.3.5 // indirect
|
github.com/benbjohnson/clock v1.3.5 // indirect
|
||||||
github.com/bits-and-blooms/bitset v1.24.2 // indirect
|
github.com/bits-and-blooms/bitset v1.24.2 // indirect
|
||||||
github.com/blendle/zapdriver v1.3.1 // indirect
|
github.com/blendle/zapdriver v1.3.1 // indirect
|
||||||
|
github.com/buger/jsonparser v1.1.1 // indirect
|
||||||
github.com/consensys/gnark-crypto v0.19.2 // indirect
|
github.com/consensys/gnark-crypto v0.19.2 // indirect
|
||||||
github.com/crate-crypto/go-eth-kzg v1.5.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/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/deckarep/golang-set/v2 v2.8.0 // indirect
|
github.com/deckarep/golang-set/v2 v2.8.0 // indirect
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
|
||||||
github.com/ethereum/c-kzg-4844/v2 v2.1.6 // indirect
|
github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect
|
||||||
github.com/ethereum/go-ethereum v1.17.2 // indirect
|
github.com/ethereum/go-ethereum v1.16.5 // indirect
|
||||||
|
github.com/ethereum/go-verkle v0.2.2 // indirect
|
||||||
github.com/fatih/color v1.18.0 // indirect
|
github.com/fatih/color v1.18.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
github.com/gagliardetto/binary v0.8.0 // indirect
|
github.com/gagliardetto/binary v0.8.0 // indirect
|
||||||
github.com/gagliardetto/solana-go v1.14.0 // indirect
|
github.com/gagliardetto/solana-go v1.14.0 // indirect
|
||||||
github.com/gagliardetto/treeout v0.1.4 // indirect
|
github.com/gagliardetto/treeout v0.1.4 // indirect
|
||||||
github.com/holiman/uint256 v1.3.2 // indirect
|
github.com/holiman/uint256 v1.3.2 // indirect
|
||||||
|
github.com/invopop/jsonschema v0.13.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/compress v1.18.1 // indirect
|
github.com/klauspost/compress v1.18.1 // indirect
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
|
github.com/logrusorgru/aurora v2.0.3+incompatible // indirect
|
||||||
|
github.com/mailru/easyjson v0.9.1 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect
|
github.com/mostynb/zstdpool-freelist v0.0.0-20201229113212-927304c0c3b1 // indirect
|
||||||
|
github.com/spf13/cast v1.10.0 // indirect
|
||||||
github.com/streamingfast/logging v0.0.0-20250918142248-ac5a1e292845 // indirect
|
github.com/streamingfast/logging v0.0.0-20250918142248-ac5a1e292845 // indirect
|
||||||
|
github.com/stretchr/testify v1.11.1 // indirect
|
||||||
github.com/supranational/blst v0.3.16 // indirect
|
github.com/supranational/blst v0.3.16 // indirect
|
||||||
github.com/tyler-smith/go-bip32 v1.0.0 // indirect
|
github.com/tyler-smith/go-bip32 v1.0.0 // indirect
|
||||||
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
|
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
|
||||||
|
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||||
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
||||||
go.mongodb.org/mongo-driver v1.17.6 // indirect
|
go.mongodb.org/mongo-driver v1.17.6 // indirect
|
||||||
go.uber.org/ratelimit v0.3.1 // indirect
|
go.uber.org/ratelimit v0.3.1 // indirect
|
||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.17.0 // indirect
|
||||||
golang.org/x/term v0.38.0 // indirect
|
golang.org/x/term v0.36.0 // indirect
|
||||||
|
gopkg.in/square/go-jose.v2 v2.6.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
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/carlmjohnson/versioninfo v0.22.5 // indirect
|
github.com/carlmjohnson/versioninfo v0.22.5 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
|
||||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||||
github.com/go-logr/logr v1.4.3 // indirect
|
github.com/go-logr/logr v1.4.2 // indirect
|
||||||
github.com/go-logr/stdr v1.2.2 // indirect
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
github.com/go-ole/go-ole v1.3.0 // indirect
|
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/google/uuid v1.6.0 // indirect
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
github.com/gorilla/websocket v1.5.1 // indirect
|
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
|
github.com/hashicorp/go-retryablehttp v0.7.5 // indirect
|
||||||
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
github.com/hashicorp/golang-lru v1.0.2 // indirect
|
||||||
|
|
@ -95,31 +97,20 @@ require (
|
||||||
github.com/multiformats/go-varint v0.0.7 // indirect
|
github.com/multiformats/go-varint v0.0.7 // indirect
|
||||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||||
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect
|
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect
|
||||||
github.com/segmentio/asm v1.2.0 // indirect
|
|
||||||
github.com/segmentio/encoding v0.5.4 // indirect
|
|
||||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
|
|
||||||
github.com/sokkalf/slog-seq v0.5.1 // indirect
|
github.com/sokkalf/slog-seq v0.5.1 // indirect
|
||||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
|
||||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
|
||||||
github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e // indirect
|
github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e // indirect
|
||||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
|
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 // indirect
|
||||||
go.opentelemetry.io/otel v1.40.0 // indirect
|
go.opentelemetry.io/otel v1.35.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.40.0 // indirect
|
go.opentelemetry.io/otel/metric v1.35.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk v1.40.0 // indirect
|
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.40.0 // indirect
|
go.opentelemetry.io/otel/trace v1.35.0 // indirect
|
||||||
go.uber.org/atomic v1.11.0 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
golang.org/x/crypto v0.46.0 // indirect
|
golang.org/x/crypto v0.43.0 // indirect
|
||||||
golang.org/x/net v0.48.0 // indirect
|
golang.org/x/sys v0.37.0 // indirect
|
||||||
golang.org/x/oauth2 v0.35.0 // indirect
|
|
||||||
golang.org/x/sys v0.41.0 // indirect
|
|
||||||
golang.org/x/text v0.32.0 // indirect
|
|
||||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
|
||||||
lukechampine.com/blake3 v1.2.1 // indirect
|
lukechampine.com/blake3 v1.2.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
220
go.sum
220
go.sum
|
|
@ -3,63 +3,41 @@ filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4
|
||||||
github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI=
|
github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI=
|
||||||
github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE=
|
github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
|
|
||||||
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
|
||||||
github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc=
|
github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e h1:ahyvB3q25YnZWly5Gq1ekg6jcmWaGj/vG/MhF4aisoc=
|
||||||
github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw=
|
github.com/FactomProject/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:kGUqhHd//musdITWjFvNTHn90WG9bMLBEPQZ17Cmlpw=
|
||||||
github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc=
|
github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec h1:1Qb69mGp/UtRPn422BH4/Y4Q3SLUrD9KHuDkm8iodFc=
|
||||||
github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U=
|
github.com/FactomProject/btcutilecc v0.0.0-20130527213604-d3a63a5752ec/go.mod h1:CD8UlnlLDiqb36L110uqiP2iSflVjx9g/3U9hCI4q2U=
|
||||||
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 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
|
||||||
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
|
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/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||||
github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU=
|
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
|
github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o=
|
||||||
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
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.24.2 h1:M7/NzVbsytmtfHbumG+K2bremQPMJuqv1JD3vOaFxp0=
|
github.com/bits-and-blooms/bitset v1.24.2 h1:M7/NzVbsytmtfHbumG+K2bremQPMJuqv1JD3vOaFxp0=
|
||||||
github.com/bits-and-blooms/bitset v1.24.2/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
github.com/bits-and-blooms/bitset v1.24.2/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE=
|
github.com/blendle/zapdriver v1.3.1 h1:C3dydBOWYRiOk+B8X9IVZ5IOe+7cl+tGOexN4QqHfpE=
|
||||||
github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc=
|
github.com/blendle/zapdriver v1.3.1/go.mod h1:mdXfREi6u5MArG4j9fewC+FGnXaBR+T4Ox4J2u4eHCc=
|
||||||
github.com/bluesky-social/indigo v0.0.0-20251009224519-09f107c1109e h1:6oNYIMh+kbArCQiwZYPGgfxQq88tnMyiBIZtg5clq90=
|
github.com/bluesky-social/indigo v0.0.0-20251009224519-09f107c1109e h1:6oNYIMh+kbArCQiwZYPGgfxQq88tnMyiBIZtg5clq90=
|
||||||
github.com/bluesky-social/indigo v0.0.0-20251009224519-09f107c1109e/go.mod h1:RuQVrCGm42QNsgumKaR6se+XkFKfCPNwdCiTvqKRUck=
|
github.com/bluesky-social/indigo v0.0.0-20251009224519-09f107c1109e/go.mod h1:RuQVrCGm42QNsgumKaR6se+XkFKfCPNwdCiTvqKRUck=
|
||||||
|
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||||
|
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||||
github.com/carlmjohnson/versioninfo v0.22.5 h1:O00sjOLUAFxYQjlN/bzYTuZiS0y6fWDQjMRvwtKgwwc=
|
github.com/carlmjohnson/versioninfo v0.22.5 h1:O00sjOLUAFxYQjlN/bzYTuZiS0y6fWDQjMRvwtKgwwc=
|
||||||
github.com/carlmjohnson/versioninfo v0.22.5/go.mod h1:QT9mph3wcVfISUKd0i9sZfVrPviHuSF+cUtLjm2WSf8=
|
github.com/carlmjohnson/versioninfo v0.22.5/go.mod h1:QT9mph3wcVfISUKd0i9sZfVrPviHuSF+cUtLjm2WSf8=
|
||||||
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
||||||
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||||
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/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw=
|
github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e h1:0XBUw73chJ1VYSsfvcPvVT7auykAJce9FpRr10L6Qhw=
|
||||||
github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA=
|
github.com/cmars/basen v0.0.0-20150613233007-fe3947df716e/go.mod h1:P13beTBKr5Q18lJe1rIoLUqjM+CB1zYrRg44ZqGuQSA=
|
||||||
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.19.2 h1:qrEAIXq3T4egxqiliFFoNrepkIWVEeIYwt3UL0fvS80=
|
github.com/consensys/gnark-crypto v0.19.2 h1:qrEAIXq3T4egxqiliFFoNrepkIWVEeIYwt3UL0fvS80=
|
||||||
github.com/consensys/gnark-crypto v0.19.2/go.mod h1:rT23F0XSZqE0mUA0+pRtnL56IbPxs6gp4CeRsBk4XS0=
|
github.com/consensys/gnark-crypto v0.19.2/go.mod h1:rT23F0XSZqE0mUA0+pRtnL56IbPxs6gp4CeRsBk4XS0=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
|
||||||
github.com/crate-crypto/go-eth-kzg v1.5.0 h1:FYRiJMJG2iv+2Dy3fi14SVGjcPteZ5HAAUe4YWlJygc=
|
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg=
|
||||||
github.com/crate-crypto/go-eth-kzg v1.5.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI=
|
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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ=
|
github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ=
|
||||||
github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
||||||
github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
|
github.com/decred/dcrd/crypto/blake256 v1.1.0 h1:zPMNGQCm0g4QTY27fOCorQW7EryeQ/U0x++OzVrdms8=
|
||||||
|
|
@ -68,18 +46,20 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvw
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
|
||||||
github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A=
|
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/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s=
|
||||||
github.com/ethereum/c-kzg-4844/v2 v2.1.6 h1:xQymkKCT5E2Jiaoqf3v4wsNgjZLY0lRSkZn27fRjSls=
|
github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s=
|
||||||
github.com/ethereum/c-kzg-4844/v2 v2.1.6/go.mod h1:8HMkUZ5JRv4hpw/XUrYWSQNAUzhHMg2UDb/U+5m+XNw=
|
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-ethereum v1.16.5 h1:GZI995PZkzP7ySCxEFaOPzS8+bd8NldE//1qvQDQpe0=
|
||||||
github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8=
|
github.com/ethereum/go-ethereum v1.16.5/go.mod h1:kId9vOtlYg3PZk9VwKbGlQmSACB5ESPTBGT+M9zjmok=
|
||||||
github.com/ethereum/go-ethereum v1.17.2 h1:ag6geu0kn8Hv5FLKTpH+Hm2DHD+iuFtuqKxEuwUsDOI=
|
github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8=
|
||||||
github.com/ethereum/go-ethereum v1.17.2/go.mod h1:KHcRXfGOUfUmKg51IhQ0IowiqZ6PqZf08CMtk0g5K1o=
|
github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk=
|
||||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||||
github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY=
|
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/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg=
|
||||||
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
github.com/gagliardetto/binary v0.8.0 h1:U9ahc45v9HW0d15LoN++vIXSJyqR/pWw8DDlhd7zvxg=
|
github.com/gagliardetto/binary v0.8.0 h1:U9ahc45v9HW0d15LoN++vIXSJyqR/pWw8DDlhd7zvxg=
|
||||||
|
|
@ -90,14 +70,11 @@ github.com/gagliardetto/solana-go v1.14.0 h1:3WfAi70jOOjAJ0deFMjdhFYlLXATF4tOQXs
|
||||||
github.com/gagliardetto/solana-go v1.14.0/go.mod h1:l/qqqIN6qJJPtxW/G1PF4JtcE3Zg2vD2EliZrr9Gn5k=
|
github.com/gagliardetto/solana-go v1.14.0/go.mod h1:l/qqqIN6qJJPtxW/G1PF4JtcE3Zg2vD2EliZrr9Gn5k=
|
||||||
github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw=
|
github.com/gagliardetto/treeout v0.1.4 h1:ozeYerrLCmCubo1TcIjFiOWTTGteOOHND1twdFpgwaw=
|
||||||
github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok=
|
github.com/gagliardetto/treeout v0.1.4/go.mod h1:loUefvXTrlRG5rYmJmExNryyBRh8f89VZhmMOyCyqok=
|
||||||
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-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
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 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
|
||||||
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
|
||||||
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
|
||||||
|
|
@ -105,33 +82,16 @@ 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/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 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
|
||||||
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.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
|
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
|
||||||
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
|
||||||
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
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/jsonschema-go v0.4.3 h1:/DBOLZTfDow7pe2GmaJNhltueGTtDKICi8V8p+DQPd0=
|
|
||||||
github.com/google/jsonschema-go v0.4.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
|
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
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/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
|
|
||||||
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
|
|
||||||
github.com/grafana/pyroscope-go v1.2.7 h1:VWBBlqxjyR0Cwk2W6UrE8CdcdD80GOFNutj0Kb1T8ac=
|
|
||||||
github.com/grafana/pyroscope-go v1.2.7/go.mod h1:o/bpSLiJYYP6HQtvcoVKiE9s5RiNgjYTj1DhiddP2Pc=
|
|
||||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.9 h1:c1Us8i6eSmkW+Ez05d3co8kasnuOY813tbMN8i/a3Og=
|
|
||||||
github.com/grafana/pyroscope-go/godeltaprof v0.1.9/go.mod h1:2+l7K7twW49Ct4wFluZD3tZ6e0SjanjcUUBPVD/UuGU=
|
|
||||||
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/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||||
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||||
|
|
@ -140,14 +100,10 @@ github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
|
||||||
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
|
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
|
||||||
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
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 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA=
|
||||||
github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||||
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
|
||||||
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
|
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
||||||
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
|
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
|
||||||
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
|
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
|
||||||
github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs=
|
github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs=
|
||||||
|
|
@ -175,8 +131,6 @@ github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY=
|
||||||
github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
|
github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
|
||||||
github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg=
|
github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg=
|
||||||
github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY=
|
github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY=
|
||||||
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/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
|
github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA=
|
||||||
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
|
github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o=
|
||||||
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
|
github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4=
|
||||||
|
|
@ -209,6 +163,10 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||||
github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8=
|
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/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
|
||||||
|
github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8=
|
||||||
|
github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||||
|
github.com/mark3labs/mcp-go v0.43.2 h1:21PUSlWWiSbUPQwXIJ5WKlETixpFpq+WBpbMGDSVy/I=
|
||||||
|
github.com/mark3labs/mcp-go v0.43.2/go.mod h1:YnJfOL382MIWDx1kMY+2zsRHU/q78dBg9aFb8W6Thdw=
|
||||||
github.com/mark3labs/x402-go v0.12.1 h1:yWlT/mjF0P1j2sB0xAM4GJb+1/Ycv6p6EqUrT6RB2X0=
|
github.com/mark3labs/x402-go v0.12.1 h1:yWlT/mjF0P1j2sB0xAM4GJb+1/Ycv6p6EqUrT6RB2X0=
|
||||||
github.com/mark3labs/x402-go v0.12.1/go.mod h1:srAvV9FosjBiqrclF15thrQbz0fVVfNXtMcqD0e1hKU=
|
github.com/mark3labs/x402-go v0.12.1/go.mod h1:srAvV9FosjBiqrclF15thrQbz0fVVfNXtMcqD0e1hKU=
|
||||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||||
|
|
@ -216,19 +174,14 @@ github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stg
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
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-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
|
||||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
|
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
|
|
||||||
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
|
github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM=
|
||||||
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
|
github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8=
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
|
github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU=
|
||||||
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
|
github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8=
|
||||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
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/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.6.1 h1:0zOSupjKUxPKSocPT1Wtago+mUHU2/uZ4xSOY0FGReU=
|
|
||||||
github.com/modelcontextprotocol/go-sdk v1.6.1/go.mod h1:kzm3kzFL1/+AziGOE0nUs3gvPoNxMCvkxokMkuFapXQ=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
|
|
@ -248,51 +201,27 @@ github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7B
|
||||||
github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=
|
github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=
|
||||||
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
|
github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8=
|
||||||
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
|
github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU=
|
||||||
github.com/nacorid/logger v0.0.0-20251221013547-5fc8fd94ed80 h1:nZwGInvJNQzPSFYpstVR/TLumqBEZt0+yUXchdyBZiI=
|
github.com/nacorid/logger v0.0.0-20251221003040-586da7a03fa0 h1:vKVU0JbEOiG7xI+UNwb8M72mo98uHCiPNyPUd9oBC9c=
|
||||||
github.com/nacorid/logger v0.0.0-20251221013547-5fc8fd94ed80/go.mod h1:hd9h4KEPU1f/Vv2qP0x/fZUwz2clFvOV/uIF0pkGo+s=
|
github.com/nacorid/logger v0.0.0-20251221003040-586da7a03fa0/go.mod h1:hd9h4KEPU1f/Vv2qP0x/fZUwz2clFvOV/uIF0pkGo+s=
|
||||||
|
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/ollama/ollama v0.12.10 h1:Dd0/SeCc+nv+FffxmWuQTGiRreib7Gt3nBhIIFuKwZA=
|
github.com/ollama/ollama v0.12.10 h1:Dd0/SeCc+nv+FffxmWuQTGiRreib7Gt3nBhIIFuKwZA=
|
||||||
github.com/ollama/ollama v0.12.10/go.mod h1:RUSmYywUWx/YZMaHrqtnT1ZChu+iSz/7jx2aO9+Mgfg=
|
github.com/ollama/ollama v0.12.10/go.mod h1:RUSmYywUWx/YZMaHrqtnT1ZChu+iSz/7jx2aO9+Mgfg=
|
||||||
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
||||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||||
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
|
||||||
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
|
||||||
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.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
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 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0=
|
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f h1:VXTQfuJj9vKR4TCkEuWIckKvdHFeJH/huIFJ9/cXOB0=
|
||||||
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
|
github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f/go.mod h1:/zvteZs/GwLtCgZ4BL6CBsk9IKIlexP43ObX9AxTqTw=
|
||||||
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
|
|
||||||
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
|
|
||||||
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
|
|
||||||
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
|
|
||||||
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
|
|
||||||
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
|
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||||
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.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
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/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
|
||||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
|
||||||
github.com/segmentio/encoding v0.5.4 h1:OW1VRern8Nw6ITAtwSZ7Idrl3MXCFwXHPgqESYfvNt0=
|
|
||||||
github.com/segmentio/encoding v0.5.4/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0=
|
|
||||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU=
|
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/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||||
|
|
@ -306,6 +235,8 @@ github.com/sokkalf/slog-seq v0.5.1 h1:4LicZGsMhuCtmZkbS++JOm3Wn8PLIrjFkuvEp0yeGH
|
||||||
github.com/sokkalf/slog-seq v0.5.1/go.mod h1:B82pc/cMpdQQg6hkBbstHEL4vqI1eZ1MISuN1IK7h14=
|
github.com/sokkalf/slog-seq v0.5.1/go.mod h1:B82pc/cMpdQQg6hkBbstHEL4vqI1eZ1MISuN1IK7h14=
|
||||||
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
|
||||||
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
|
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||||
|
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||||
github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU=
|
github.com/streamingfast/logging v0.0.0-20230608130331-f22c91403091/go.mod h1:VlduQ80JcGJSargkRU4Sg9Xo63wZD/l8A5NC/Uo1/uU=
|
||||||
github.com/streamingfast/logging v0.0.0-20250918142248-ac5a1e292845 h1:VMA0pZ3MI8BErRA3kh8dKJThP5d0Xh5vZVk5yFIgH/A=
|
github.com/streamingfast/logging v0.0.0-20250918142248-ac5a1e292845 h1:VMA0pZ3MI8BErRA3kh8dKJThP5d0Xh5vZVk5yFIgH/A=
|
||||||
github.com/streamingfast/logging v0.0.0-20250918142248-ac5a1e292845/go.mod h1:BtDq81Tyc7H8up5aXNi/I95nPmG3C0PLEqGWY/iWQ2E=
|
github.com/streamingfast/logging v0.0.0-20250918142248-ac5a1e292845/go.mod h1:BtDq81Tyc7H8up5aXNi/I95nPmG3C0PLEqGWY/iWQ2E=
|
||||||
|
|
@ -319,8 +250,6 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
|
||||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/supranational/blst v0.3.16 h1:bTDadT+3fK497EvLdWRQEjiGnUtzJ7jjIUMF0jqwYhE=
|
github.com/supranational/blst v0.3.16 h1:bTDadT+3fK497EvLdWRQEjiGnUtzJ7jjIUMF0jqwYhE=
|
||||||
github.com/supranational/blst v0.3.16/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
github.com/supranational/blst v0.3.16/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/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
|
github.com/test-go/testify v1.1.4 h1:Tf9lntrKUMHiXQ07qBScBTSA0dhYQlu83hswqelv1iE=
|
||||||
github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
|
github.com/test-go/testify v1.1.4/go.mod h1:rH7cfJo/47vWGdi4GPj16x3/t1xGOj2YxzmNQzk2ghU=
|
||||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||||
|
|
@ -331,24 +260,13 @@ github.com/tyler-smith/go-bip32 v1.0.0 h1:sDR9juArbUgX+bO/iblgZnMPeWY1KZMUC2AFUJ
|
||||||
github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE=
|
github.com/tyler-smith/go-bip32 v1.0.0/go.mod h1:onot+eHknzV4BVPwrzqY5OoVpyCvnwD7lMawL5aQupE=
|
||||||
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
|
github.com/tyler-smith/go-bip39 v1.1.0 h1:5eUemwrMargf3BSLRRCalXT93Ns6pQJIjYQN2nyfOP8=
|
||||||
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
|
github.com/tyler-smith/go-bip39 v1.1.0/go.mod h1:gUYDtqQw1JS3ZJ8UWVcGTGqqr6YIN3CWg+kkNaLt55U=
|
||||||
github.com/urfave/cli v1.22.10 h1:p8Fspmz3iTctJstry1PYS3HVdllxnEzTEsgIgtxTrCk=
|
|
||||||
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
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/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
|
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
|
||||||
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
|
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
|
||||||
github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e h1:28X54ciEwwUxyHn9yrZfl5ojgF4CBNLWX7LR0rvBkf4=
|
github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e h1:28X54ciEwwUxyHn9yrZfl5ojgF4CBNLWX7LR0rvBkf4=
|
||||||
github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so=
|
github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so=
|
||||||
github.com/x402-foundation/x402/go/v2 v2.19.0 h1:vyU9cKFfqw8oI6To66r+UH67vFwWpoMDRX9zGM8bCJI=
|
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
||||||
github.com/x402-foundation/x402/go/v2 v2.19.0/go.mod h1:OAsOuB+FYhCoKzijOGZ+PcJk9g4RBfCJvpABGxi+NcE=
|
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||||
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 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
||||||
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
|
|
@ -356,20 +274,18 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss=
|
go.mongodb.org/mongo-driver v1.17.6 h1:87JUG1wZfWsr6rIz3ZmpH90rL5tea7O3IHuSwHUpsss=
|
||||||
go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
go.mongodb.org/mongo-driver v1.17.6/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1 h1:aFJWCqJMNjENlcleuuOkGAPH82y0yULBScfXcIEdS24=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.46.1/go.mod h1:sEGXWArGqc3tVa+ekntsN65DmVbVeW+7lTKTjZF3/Fo=
|
||||||
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
|
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||||
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
|
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||||
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
|
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||||
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
|
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||||
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
|
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||||
go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
|
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
|
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
|
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||||
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
|
|
||||||
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
|
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
|
@ -399,10 +315,8 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU=
|
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||||
golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0=
|
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY=
|
|
||||||
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
|
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
|
|
@ -415,19 +329,16 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
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-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||||
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||||
golang.org/x/oauth2 v0.35.0 h1:Mv2mzuHuZuY2+bkyWXIHMfhNdJAdwW3FuWeCPYN5GVQ=
|
|
||||||
golang.org/x/oauth2 v0.35.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/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-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.17.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-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-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|
@ -435,20 +346,17 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
|
||||||
golang.org/x/sys v0.41.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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q=
|
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||||
golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg=
|
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||||
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
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/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-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
|
@ -461,23 +369,19 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.42.0 h1:uNgphsn75Tdz5Ji2q36v/nsFSfR/9BRFvqhGBaJGd5k=
|
|
||||||
golang.org/x/tools v0.42.0/go.mod h1:Ma6lCIwGZvHK6XtgbswSoWroEkhugApmsXyrUmBhfr0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
|
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
|
||||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
|
|
||||||
|
|
@ -1,84 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/rand"
|
|
||||||
"crypto/x509"
|
|
||||||
"encoding/hex"
|
|
||||||
"encoding/pem"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v5"
|
|
||||||
x402http "github.com/x402-foundation/x402/go/v2/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CDPAuth struct {
|
|
||||||
keyName string
|
|
||||||
privateKey *ecdsa.PrivateKey
|
|
||||||
signingMethod jwt.SigningMethod
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCDPAuth(keyName, privateKeyPEM string) (*CDPAuth, error) {
|
|
||||||
block, _ := pem.Decode([]byte(privateKeyPEM))
|
|
||||||
if block == nil {
|
|
||||||
return nil, fmt.Errorf("failed to decode PEM block")
|
|
||||||
}
|
|
||||||
|
|
||||||
var signingMethod jwt.SigningMethod
|
|
||||||
privKey, err := x509.ParseECPrivateKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
parsed, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to parse private key: %w", err)
|
|
||||||
}
|
|
||||||
var ok bool
|
|
||||||
privKey, ok = parsed.(*ecdsa.PrivateKey)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("not an ECDSA private key")
|
|
||||||
}
|
|
||||||
signingMethod = jwt.SigningMethodEdDSA
|
|
||||||
} else {
|
|
||||||
signingMethod = jwt.SigningMethodES256
|
|
||||||
}
|
|
||||||
return &CDPAuth{
|
|
||||||
keyName: keyName,
|
|
||||||
privateKey: privKey,
|
|
||||||
signingMethod: signingMethod,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *CDPAuth) generateBearerToken(method, path string) (string, error) {
|
|
||||||
nonceBytes := make([]byte, 16)
|
|
||||||
if _, err := rand.Read(nonceBytes); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
nonce := hex.EncodeToString(nonceBytes)
|
|
||||||
uri := fmt.Sprintf("%s api.cdp.coinbase.com%s", method, path)
|
|
||||||
now := time.Now().Unix()
|
|
||||||
claims := jwt.MapClaims{
|
|
||||||
"sub": a.keyName,
|
|
||||||
"iss": "cdp",
|
|
||||||
"nbf": now,
|
|
||||||
"exp": now + 120,
|
|
||||||
"uris": []string{uri},
|
|
||||||
}
|
|
||||||
|
|
||||||
token := jwt.NewWithClaims(a.signingMethod, claims)
|
|
||||||
token.Header["kid"] = a.keyName
|
|
||||||
token.Header["nonce"] = nonce
|
|
||||||
|
|
||||||
return token.SignedString(a.privateKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *CDPAuth) GetAuthHeaders(ctx context.Context) (x402http.AuthHeaders, error) {
|
|
||||||
verify, _ := a.generateBearerToken("POST", "/platform/v2/x402/verify")
|
|
||||||
settle, _ := a.generateBearerToken("POST", "/platform/v2/x402/settle")
|
|
||||||
supported, _ := a.generateBearerToken("GET", "/platform/v2/x402/supported")
|
|
||||||
return x402http.AuthHeaders{
|
|
||||||
Verify: map[string]string{"Authorization": "Bearer " + verify},
|
|
||||||
Settle: map[string]string{"Authorization": "Bearer " + settle},
|
|
||||||
Supported: map[string]string{"Authorization": "Bearer " + supported},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
@ -5,7 +5,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
|
"github.com/mark3labs/mcp-go/server"
|
||||||
log "github.com/nacorid/logger"
|
log "github.com/nacorid/logger"
|
||||||
"github.com/nacorid/naco-api/internal/utils"
|
"github.com/nacorid/naco-api/internal/utils"
|
||||||
)
|
)
|
||||||
|
|
@ -22,18 +23,15 @@ func NewMetricsHook() *MetricsMiddleware {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mh *MetricsMiddleware) OnCall(next mcp.MethodHandler) mcp.MethodHandler {
|
func (mh *MetricsMiddleware) OnCall(next server.ToolHandlerFunc) server.ToolHandlerFunc {
|
||||||
return func(ctx context.Context, method string, request mcp.Request) (mcp.Result, error) {
|
return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
if method == "tools/call" {
|
start := time.Now()
|
||||||
start := time.Now()
|
mh.requestsBucket.Increment()
|
||||||
mh.requestsBucket.Increment()
|
mh.totalRequests.Increment()
|
||||||
mh.totalRequests.Increment()
|
result, err := next(ctx, request)
|
||||||
result, err := next(ctx, method, request)
|
duration := time.Since(start)
|
||||||
duration := time.Since(start)
|
log.DebugWithContext(ctx, "MetricsMiddleware: MCP Handler", "duration", duration)
|
||||||
log.DebugWithContext(ctx, "MetricsMiddleware: MCP Handler", "duration", duration)
|
return result, err
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
return next(ctx, method, request)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,8 +8,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
log "github.com/nacorid/logger"
|
"github.com/mark3labs/mcp-go/server"
|
||||||
"golang.org/x/time/rate"
|
"golang.org/x/time/rate"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -45,32 +45,23 @@ func (m *RateLimitMiddleware) getLimiter(sessionID string) *rate.Limiter {
|
||||||
return limiter
|
return limiter
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *RateLimitMiddleware) OnCall(next mcp.MethodHandler) mcp.MethodHandler {
|
func (m *RateLimitMiddleware) OnCall(next server.ToolHandlerFunc) server.ToolHandlerFunc {
|
||||||
return func(ctx context.Context, method string, req mcp.Request) (mcp.Result, error) {
|
return func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||||
if method == "tools/call" {
|
if slices.Contains(m.request, req.Params.Name) {
|
||||||
callReq, ok := req.(*mcp.CallToolRequest)
|
var sessionID string
|
||||||
if ok && slices.Contains(m.request, callReq.Params.Name) {
|
session := server.ClientSessionFromContext(ctx)
|
||||||
var sessionID string
|
if session == nil {
|
||||||
session := req.GetSession()
|
sessionID = getClientIP(req.Header)
|
||||||
if session == nil || session.ID() == "" {
|
} else {
|
||||||
if extra := req.GetExtra(); extra != nil {
|
sessionID = session.SessionID()
|
||||||
sessionID = getClientIP(req.GetExtra().Header)
|
}
|
||||||
} else {
|
limiter := m.getLimiter(sessionID)
|
||||||
log.WarnWithContext(ctx, "No session or extra information found in request; using 'unknown' as session ID")
|
|
||||||
sessionID = "unknown"
|
if !limiter.Allow() {
|
||||||
}
|
return nil, fmt.Errorf("rate limit exceeded for session %s\nRatelimit: %v requests per second", sessionID, limiter.Limit())
|
||||||
} else {
|
|
||||||
sessionID = session.ID()
|
|
||||||
}
|
|
||||||
limiter := m.getLimiter(sessionID)
|
|
||||||
|
|
||||||
if !limiter.Allow() {
|
|
||||||
return nil, fmt.Errorf("rate limit exceeded for session %s\nRatelimit: %v requests per second", sessionID, limiter.Limit())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return next(ctx, method, req)
|
|
||||||
}
|
}
|
||||||
return next(ctx, method, req)
|
return next(ctx, req)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -10,7 +9,11 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bluesky-social/indigo/api/bsky"
|
"github.com/bluesky-social/indigo/api/bsky"
|
||||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
|
mcpserver "github.com/mark3labs/mcp-go/server"
|
||||||
|
x402go "github.com/mark3labs/x402-go"
|
||||||
|
x402http "github.com/mark3labs/x402-go/http"
|
||||||
|
"github.com/mark3labs/x402-go/signers/coinbase"
|
||||||
log "github.com/nacorid/logger"
|
log "github.com/nacorid/logger"
|
||||||
"github.com/nacorid/naco-api/internal/activitypub"
|
"github.com/nacorid/naco-api/internal/activitypub"
|
||||||
"github.com/nacorid/naco-api/internal/bluesky"
|
"github.com/nacorid/naco-api/internal/bluesky"
|
||||||
|
|
@ -19,9 +22,6 @@ import (
|
||||||
"github.com/nacorid/naco-api/internal/store"
|
"github.com/nacorid/naco-api/internal/store"
|
||||||
"github.com/nacorid/naco-api/internal/utils"
|
"github.com/nacorid/naco-api/internal/utils"
|
||||||
"github.com/nacorid/naco-api/internal/x402"
|
"github.com/nacorid/naco-api/internal/x402"
|
||||||
x402v2 "github.com/x402-foundation/x402/go/v2"
|
|
||||||
x402http "github.com/x402-foundation/x402/go/v2/http/nethttp"
|
|
||||||
"github.com/x402-foundation/x402/go/v2/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
|
|
@ -39,7 +39,7 @@ func New(ctx context.Context, db *store.Queries, ap *activitypub.APClient, bsky
|
||||||
rateLimits := NewRateLimitMiddleware(float64(1.0/10.0), 2, []string{"getFeed"})
|
rateLimits := NewRateLimitMiddleware(float64(1.0/10.0), 2, []string{"getFeed"})
|
||||||
metrics := NewMetricsHook()
|
metrics := NewMetricsHook()
|
||||||
toolChain := x402.X402Middlewares{
|
toolChain := x402.X402Middlewares{
|
||||||
MCPMiddleware: []mcp.Middleware{
|
MCPMiddleware: []mcpserver.ToolHandlerMiddleware{
|
||||||
metrics.OnCall,
|
metrics.OnCall,
|
||||||
rateLimits.OnCall,
|
rateLimits.OnCall,
|
||||||
},
|
},
|
||||||
|
|
@ -48,43 +48,86 @@ func New(ctx context.Context, db *store.Queries, ap *activitypub.APClient, bsky
|
||||||
rateLimits.OnCallHTTP,
|
rateLimits.OnCallHTTP,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
auth, err := NewCDPAuth(cfg.ApiKey, cfg.ApiSecret)
|
auth, err := coinbase.NewCDPAuth(cfg.ApiKey, cfg.ApiSecret, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FatalWithContext(ctx, "failed to create CDP auth", "error", err)
|
log.FatalWithContext(ctx, "failed to create CDP auth", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
srv, err := x402.NewX402Server(
|
srv, err := x402.NewX402Server(
|
||||||
"x402 enabled Bluesky lookingglass for autonomous Agents",
|
"x402 enabled Bluesky lookingglass for autonomous Agents",
|
||||||
"0.2.0",
|
"0.1.0",
|
||||||
cfg.X402FacilitatorURL,
|
&x402http.Config{
|
||||||
auth,
|
FacilitatorURL: cfg.X402FacilitatorURL,
|
||||||
toolChain,
|
FacilitatorAuthorizationProvider: func(r *http.Request) string {
|
||||||
func(w http.ResponseWriter, r *http.Request, resp *x402v2.SettleResponse) {
|
token, err := auth.GenerateBearerToken(r.Method, r.URL.Path)
|
||||||
requirements, ok := x402http.RequirementsFromContext(r.Context())
|
if err != nil {
|
||||||
if !ok {
|
log.FatalWithContext(ctx, "failed to generate auth token", "error", err)
|
||||||
log.WarnWithContext(r.Context(), "failed to extract payment requirements from context during settlement hook")
|
return ""
|
||||||
return
|
}
|
||||||
}
|
return "Bearer " + token
|
||||||
|
},
|
||||||
amount := requirements.Amount
|
FacilitatorOnAfterSettle: func(ctx context.Context, pp x402go.PaymentPayload, pr x402go.PaymentRequirement, sr *x402go.SettlementResponse, errVal error) {
|
||||||
asset := requirements.Asset
|
var amount string
|
||||||
to := requirements.PayTo
|
if errVal != nil {
|
||||||
_ = settleHook(r.Context(), db, resp.Transaction, amount, asset, string(resp.Network), to, resp.Payer)
|
log.ErrorWithContext(ctx, "Payment settlement failed", "error", errVal)
|
||||||
|
amount = "0"
|
||||||
|
} else {
|
||||||
|
if payload, ok := pp.Payload.(map[string]interface{}); ok {
|
||||||
|
if auth, ok := payload["Authorization"].(map[string]interface{}); ok {
|
||||||
|
if value, ok := auth["Value"].(string); ok {
|
||||||
|
amount = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var to string
|
||||||
|
if payload, ok := pp.Payload.(map[string]interface{}); ok {
|
||||||
|
if auth, ok := payload["Authorization"].(map[string]interface{}); ok {
|
||||||
|
if value, ok := auth["To"].(string); ok {
|
||||||
|
to = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var from string
|
||||||
|
if payload, ok := pp.Payload.(map[string]interface{}); ok {
|
||||||
|
if auth, ok := payload["Authorization"].(map[string]interface{}); ok {
|
||||||
|
if value, ok := auth["From"].(string); ok {
|
||||||
|
from = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret, err := db.SaveTransaction(ctx, store.SaveTransactionParams{
|
||||||
|
X402TransactionHash: sr.Transaction,
|
||||||
|
Amount: amount,
|
||||||
|
Asset: pr.Asset,
|
||||||
|
Network: sr.Network,
|
||||||
|
Recipient: to,
|
||||||
|
Sender: from,
|
||||||
|
})
|
||||||
|
var id int64 = 0
|
||||||
|
if len(ret) > 0 {
|
||||||
|
id = ret[0].ID
|
||||||
|
}
|
||||||
|
fields := log.Fields{
|
||||||
|
"transaction_id": id,
|
||||||
|
"X402_transaction_hash": sr.Transaction,
|
||||||
|
"amount": amount,
|
||||||
|
"asset": pr.Asset,
|
||||||
|
"network": sr.Network,
|
||||||
|
"recipient": to,
|
||||||
|
"sender": from,
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.WithFields(fields).ErrorWithContext(ctx, "Failed to save transaction", "value", ret, "error", err)
|
||||||
|
}
|
||||||
|
log.WithFields(fields).DebugWithContext(ctx, "Saved transaction")
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
toolChain,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.FatalWithContext(ctx, "failed to create x402 server", "error", err)
|
log.FatalWithContext(ctx, "failed to create x402 server", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
srv.OnAfterSettle(func(settleCtx x402v2.SettleResultContext) error {
|
|
||||||
amount := settleCtx.Requirements.GetAmount()
|
|
||||||
asset := settleCtx.Requirements.GetAsset()
|
|
||||||
to := settleCtx.Requirements.GetPayTo()
|
|
||||||
from := settleCtx.Result.Payer
|
|
||||||
|
|
||||||
return settleHook(settleCtx.Ctx, db, settleCtx.Result.Transaction, amount, asset, string(settleCtx.Result.Network), to, from)
|
|
||||||
})
|
|
||||||
|
|
||||||
s := &Server{
|
s := &Server{
|
||||||
listenAddress: cfg.ListenAddress,
|
listenAddress: cfg.ListenAddress,
|
||||||
permissions: cfg.UnixSocketPermissions,
|
permissions: cfg.UnixSocketPermissions,
|
||||||
|
|
@ -102,253 +145,244 @@ func New(ctx context.Context, db *store.Queries, ap *activitypub.APClient, bsky
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) registerTools() {
|
func (s *Server) registerTools() {
|
||||||
extra := map[string]any{
|
chainConfig := x402go.BaseMainnet
|
||||||
"OutputSchema": Schema{
|
|
||||||
Input: InputSchema{
|
requirement, err := newUSDCPaymentRequirement(x402go.USDCRequirementConfig{
|
||||||
Type: "HTTP",
|
Chain: chainConfig,
|
||||||
Method: "POST",
|
Amount: "0.01",
|
||||||
Discoverable: true,
|
RecipientAddress: s.x402Wallet,
|
||||||
BodyFields: map[string]any{
|
Description: "Get a specific post from a specific actor",
|
||||||
"actor": Bodyfield{
|
MaxTimeoutSeconds: 60,
|
||||||
|
},
|
||||||
|
&x402go.OutputSchema{
|
||||||
|
Input: x402go.InputSchema{
|
||||||
|
Type: x402go.InputSchemaTypeHTTP,
|
||||||
|
Method: x402go.InputSchemaMethodPOST,
|
||||||
|
BodyType: x402go.InputSchemaBodyTypeJSON,
|
||||||
|
BodyFields: map[string]x402go.FieldDef{
|
||||||
|
"actor": {
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Description: "Did or handle of an actor",
|
Description: "Did or handle of an actor",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
"rkey": Bodyfield{
|
"rkey": {
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Description: "Record key of the post",
|
Description: "Record key of the post",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
"collection": Bodyfield{
|
"collection": {
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Description: "Collection the post belongs to. Defaults to 'app.bsky.feed.post'",
|
Description: "Collection the post belongs to. Defaults to 'app.bsky.feed.post'",
|
||||||
Required: false,
|
Required: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Output: map[string]any{
|
Output: map[string]x402go.FieldDef{
|
||||||
"actor": Bodyfield{
|
"actor": {
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Description: "Did of the actor",
|
Description: "Did of the actor",
|
||||||
},
|
},
|
||||||
"post": Bodyfield{
|
"post": {
|
||||||
Type: "object",
|
Type: "object",
|
||||||
Description: "The post object. Includes the post content 'content', like 'likes', quote 'quotes', replies 'replies' and repost 'reposts' count",
|
Description: "The post object. Includes the post content 'content', like 'likes', quote 'quotes', replies 'replies' and repost 'reposts' count",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed to create payment requirement", "error", err)
|
||||||
}
|
}
|
||||||
|
requirements := []x402go.PaymentRequirement{requirement}
|
||||||
requirement := types.PaymentRequirements{
|
|
||||||
Scheme: "exact",
|
|
||||||
Network: "eip155:8453",
|
|
||||||
Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
||||||
Amount: "10000",
|
|
||||||
PayTo: s.x402Wallet,
|
|
||||||
MaxTimeoutSeconds: 60,
|
|
||||||
Extra: extra,
|
|
||||||
}
|
|
||||||
requirements := []types.PaymentRequirements{requirement}
|
|
||||||
s.mcpHandler.AddPayableTool(
|
s.mcpHandler.AddPayableTool(
|
||||||
mcp.Tool{Name: "getPost",
|
mcp.NewTool("getPost",
|
||||||
Description: "Get a specific post from a specific actor",
|
mcp.WithDescription("Get a specific post from a specific actor"),
|
||||||
InputSchema: GetPostRequest{},
|
mcp.WithInputSchema[GetPostRequest](),
|
||||||
OutputSchema: GetPostResponsePost{},
|
mcp.WithOutputSchema[GetPostResponsePost](),
|
||||||
},
|
),
|
||||||
s.getPost,
|
mcp.NewStructuredToolHandler(s.getPost),
|
||||||
requirements...,
|
requirements...,
|
||||||
)
|
)
|
||||||
|
|
||||||
extra = map[string]any{
|
requirement, err = newUSDCPaymentRequirement(x402go.USDCRequirementConfig{
|
||||||
"OutputSchema": Schema{
|
Chain: chainConfig,
|
||||||
Input: InputSchema{
|
Amount: "0.10",
|
||||||
Type: "HTTP",
|
RecipientAddress: s.x402Wallet,
|
||||||
Method: "POST",
|
Description: "Get the latest n posts from a specific actor",
|
||||||
Discoverable: true,
|
MaxTimeoutSeconds: 60,
|
||||||
BodyFields: map[string]any{
|
},
|
||||||
"actor": Bodyfield{
|
&x402go.OutputSchema{
|
||||||
|
Input: x402go.InputSchema{
|
||||||
|
Type: x402go.InputSchemaTypeHTTP,
|
||||||
|
Method: x402go.InputSchemaMethodPOST,
|
||||||
|
BodyType: x402go.InputSchemaBodyTypeJSON,
|
||||||
|
BodyFields: map[string]x402go.FieldDef{
|
||||||
|
"actor": {
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Description: "Did or handle of an actor",
|
Description: "Did or handle of an actor",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
"n": Bodyfield{
|
"n": {
|
||||||
Type: "integer",
|
Type: "integer",
|
||||||
Description: "Number of posts to retrieve, maximum 50",
|
Description: "Number of posts to retrieve, maximum 50",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Output: map[string]any{
|
Output: map[string]x402go.FieldDef{
|
||||||
"actor": Bodyfield{
|
"actor": {
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Description: "Did of an actor",
|
Description: "Did of an actor",
|
||||||
},
|
},
|
||||||
"posts": Bodyfield{
|
"posts": {
|
||||||
Type: "array",
|
Type: "array",
|
||||||
Description: "Array of post objects. Each includes the post content 'content', like 'likes', quote 'quotes', replies 'replies' and repost 'reposts' count",
|
Description: "Array of post objects. Each includes the post content 'content', like 'likes', quote 'quotes', replies 'replies' and repost 'reposts' count",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed to create payment requirement", "error", err)
|
||||||
}
|
}
|
||||||
|
requirements = []x402go.PaymentRequirement{requirement}
|
||||||
requirement = types.PaymentRequirements{
|
|
||||||
Scheme: "exact",
|
|
||||||
Network: "eip155:8453",
|
|
||||||
Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
||||||
Amount: "100000",
|
|
||||||
PayTo: s.x402Wallet,
|
|
||||||
MaxTimeoutSeconds: 60,
|
|
||||||
Extra: extra,
|
|
||||||
}
|
|
||||||
|
|
||||||
requirements = []types.PaymentRequirements{requirement}
|
|
||||||
|
|
||||||
s.mcpHandler.AddPayableTool(
|
s.mcpHandler.AddPayableTool(
|
||||||
mcp.Tool{Name: "getLatestPosts",
|
mcp.NewTool("getLatestPosts",
|
||||||
Description: "Get the latest n posts from a specific actor",
|
mcp.WithDescription("Get the latest n posts from a specific actor"),
|
||||||
InputSchema: GetLatestPostsRequest{},
|
mcp.WithInputSchema[GetLatestPostsRequest](),
|
||||||
OutputSchema: GetLatestPostsResponse{},
|
mcp.WithOutputSchema[GetLatestPostsResponse](),
|
||||||
},
|
),
|
||||||
s.getLatestPosts,
|
mcp.NewStructuredToolHandler(s.getLatestPosts),
|
||||||
requirements...,
|
requirements...,
|
||||||
)
|
)
|
||||||
|
|
||||||
extra = map[string]any{
|
requirement, err = newUSDCPaymentRequirement(x402go.USDCRequirementConfig{
|
||||||
"OutputSchema": Schema{
|
Chain: chainConfig,
|
||||||
Input: InputSchema{
|
Amount: "0.10",
|
||||||
Type: "HTTP",
|
RecipientAddress: s.x402Wallet,
|
||||||
Method: "POST",
|
Description: "Get posts from a specific actor in a time range",
|
||||||
Discoverable: true,
|
MaxTimeoutSeconds: 60,
|
||||||
BodyFields: map[string]any{
|
},
|
||||||
"actor": Bodyfield{
|
&x402go.OutputSchema{
|
||||||
|
Input: x402go.InputSchema{
|
||||||
|
Type: x402go.InputSchemaTypeHTTP,
|
||||||
|
Method: x402go.InputSchemaMethodPOST,
|
||||||
|
BodyType: x402go.InputSchemaBodyTypeJSON,
|
||||||
|
BodyFields: map[string]x402go.FieldDef{
|
||||||
|
"actor": {
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Description: "Did or handle of an actor",
|
Description: "Did or handle of an actor",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
"start": Bodyfield{
|
"start": {
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Description: "Start time in RFC3339 format",
|
Description: "Start time in RFC3339 format",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
"end": Bodyfield{
|
"end": {
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Description: "End time in RFC3339 format",
|
Description: "End time in RFC3339 format",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
"n": Bodyfield{
|
"n": {
|
||||||
Type: "integer",
|
Type: "integer",
|
||||||
Description: "Maximum number of posts to retrieve, maximum 50",
|
Description: "Maximum number of posts to retrieve, maximum 50",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Output: map[string]any{
|
Output: map[string]x402go.FieldDef{
|
||||||
"actor": Bodyfield{
|
"actor": {
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Description: "Did of an actor",
|
Description: "Did of an actor",
|
||||||
},
|
},
|
||||||
"posts": Bodyfield{
|
"posts": {
|
||||||
Type: "array",
|
Type: "array",
|
||||||
Description: "Array of post objects. Each includes the post content 'content', like 'likes', quote 'quotes', replies 'replies' and repost 'reposts' count",
|
Description: "Array of post objects. Each includes the post content 'content', like 'likes', quote 'quotes', replies 'replies' and repost 'reposts' count",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed to create payment requirement", "error", err)
|
||||||
}
|
}
|
||||||
|
requirements = []x402go.PaymentRequirement{requirement}
|
||||||
requirement = types.PaymentRequirements{
|
|
||||||
Scheme: "exact",
|
|
||||||
Network: "eip155:8453",
|
|
||||||
Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
||||||
Amount: "100000",
|
|
||||||
PayTo: s.x402Wallet,
|
|
||||||
MaxTimeoutSeconds: 60,
|
|
||||||
Extra: extra,
|
|
||||||
}
|
|
||||||
|
|
||||||
requirements = []types.PaymentRequirements{requirement}
|
|
||||||
|
|
||||||
s.mcpHandler.AddPayableTool(
|
s.mcpHandler.AddPayableTool(
|
||||||
mcp.Tool{Name: "getPostsInTime",
|
mcp.NewTool("getPostsInTime",
|
||||||
Description: "Get posts from a specific actor in a time range",
|
mcp.WithDescription("Get posts from a specific actor in a time range"),
|
||||||
InputSchema: GetPostsInTimeRequest{},
|
mcp.WithInputSchema[GetPostsInTimeRequest](),
|
||||||
OutputSchema: GetPostsInTimeResponse{},
|
mcp.WithOutputSchema[GetPostsInTimeResponse](),
|
||||||
},
|
),
|
||||||
s.getPostsInTime,
|
mcp.NewStructuredToolHandler(s.getPostsInTime),
|
||||||
requirements...,
|
requirements...,
|
||||||
)
|
)
|
||||||
|
|
||||||
extra = map[string]any{
|
requirement, err = newUSDCPaymentRequirement(x402go.USDCRequirementConfig{
|
||||||
"OutputSchema": Schema{
|
Chain: chainConfig,
|
||||||
Input: InputSchema{
|
Amount: "0.50",
|
||||||
Type: "HTTP",
|
RecipientAddress: s.x402Wallet,
|
||||||
Method: "POST",
|
Description: "Get an actor's style Profile",
|
||||||
Discoverable: true,
|
MaxTimeoutSeconds: 60,
|
||||||
BodyFields: map[string]any{
|
},
|
||||||
"actor": Bodyfield{
|
&x402go.OutputSchema{
|
||||||
|
Input: x402go.InputSchema{
|
||||||
|
Type: x402go.InputSchemaTypeHTTP,
|
||||||
|
Method: x402go.InputSchemaMethodPOST,
|
||||||
|
BodyType: x402go.InputSchemaBodyTypeJSON,
|
||||||
|
BodyFields: map[string]x402go.FieldDef{
|
||||||
|
"actor": {
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Description: "Did or handle of an actor",
|
Description: "Did or handle of an actor",
|
||||||
Required: true,
|
Required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Output: map[string]any{
|
Output: map[string]x402go.FieldDef{
|
||||||
"PersonaEmbedding": Bodyfield{
|
"PersonaEmbedding": {
|
||||||
Type: "array",
|
Type: "array",
|
||||||
Description: "Embedding vector representing the actor's persona",
|
Description: "Embedding vector representing the actor's persona",
|
||||||
},
|
},
|
||||||
"TopKeywords": Bodyfield{
|
"TopKeywords": {
|
||||||
Type: "array",
|
Type: "array",
|
||||||
Description: "Top words used by the actor",
|
Description: "Top words used by the actor",
|
||||||
},
|
},
|
||||||
"StyleSummary": Bodyfield{
|
"StyleSummary": {
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Description: "Summary of the actor's writing style",
|
Description: "Summary of the actor's writing style",
|
||||||
},
|
},
|
||||||
"PostCount": Bodyfield{
|
"PostCount": {
|
||||||
Type: "integer",
|
Type: "integer",
|
||||||
Description: "Number of posts analyzed",
|
Description: "Number of posts analyzed",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed to create payment requirement", "error", err)
|
||||||
}
|
}
|
||||||
|
requirements = []x402go.PaymentRequirement{requirement}
|
||||||
requirement = types.PaymentRequirements{
|
|
||||||
Scheme: "exact",
|
|
||||||
Network: "eip155:8453",
|
|
||||||
Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
||||||
Amount: "100000",
|
|
||||||
PayTo: s.x402Wallet,
|
|
||||||
MaxTimeoutSeconds: 60,
|
|
||||||
Extra: extra,
|
|
||||||
}
|
|
||||||
|
|
||||||
requirements = []types.PaymentRequirements{requirement}
|
|
||||||
|
|
||||||
s.mcpHandler.AddPayableTool(
|
s.mcpHandler.AddPayableTool(
|
||||||
mcp.Tool{Name: "getStyleProfile",
|
mcp.NewTool("getStyleProfile",
|
||||||
Description: "Get an actor's style Profile",
|
mcp.WithDescription("Get an actor's style Profile"),
|
||||||
InputSchema: GetStyleProfileRequest{},
|
mcp.WithInputSchema[GetStyleProfileRequest](),
|
||||||
OutputSchema: GetStyleProfileResponse{},
|
mcp.WithOutputSchema[GetStyleProfileResponse](),
|
||||||
},
|
),
|
||||||
s.getStyleProfile,
|
mcp.NewStructuredToolHandler(s.getStyleProfile),
|
||||||
requirements...,
|
requirements...,
|
||||||
)
|
)
|
||||||
|
|
||||||
s.mcpHandler.AddTool(
|
s.mcpHandler.AddTool(
|
||||||
mcp.Tool{Name: "getFeed",
|
mcp.NewTool("getFeed",
|
||||||
Description: "Get a feed by its URI",
|
mcp.WithDescription("Get a feed by its URI"),
|
||||||
InputSchema: GetFeedRequest{},
|
mcp.WithInputSchema[GetFeedRequest](),
|
||||||
OutputSchema: GetFeedResponse{},
|
mcp.WithOutputSchema[GetFeedResponse](),
|
||||||
},
|
),
|
||||||
s.getFeed,
|
mcp.NewStructuredToolHandler(s.getFeed),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getPost(ctx context.Context, request *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func (s *Server) getPost(ctx context.Context, request mcp.CallToolRequest, args GetPostRequest) (*GetPostResponsePost, error) {
|
||||||
var args GetPostRequest
|
|
||||||
if err := json.Unmarshal(request.Params.Arguments, &args); err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid arguments: %w", err)
|
|
||||||
}
|
|
||||||
if args.Author == "" {
|
if args.Author == "" {
|
||||||
return nil, fmt.Errorf("author must be a valid did or handle")
|
return nil, fmt.Errorf("author must be a valid did or handle")
|
||||||
}
|
}
|
||||||
|
|
@ -363,7 +397,7 @@ func (s *Server) getPost(ctx context.Context, request *mcp.CallToolRequest) (*mc
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("record is not a feed post")
|
return nil, fmt.Errorf("record is not a feed post")
|
||||||
}
|
}
|
||||||
resp := GetPostResponsePost{
|
return &GetPostResponsePost{
|
||||||
Author: res.Author.Did,
|
Author: res.Author.Did,
|
||||||
Content: post.Text,
|
Content: post.Text,
|
||||||
Likes: *res.LikeCount,
|
Likes: *res.LikeCount,
|
||||||
|
|
@ -371,25 +405,10 @@ func (s *Server) getPost(ctx context.Context, request *mcp.CallToolRequest) (*mc
|
||||||
Quotes: *res.QuoteCount,
|
Quotes: *res.QuoteCount,
|
||||||
Replies: *res.ReplyCount,
|
Replies: *res.ReplyCount,
|
||||||
CreatedAt: post.CreatedAt,
|
CreatedAt: post.CreatedAt,
|
||||||
}
|
|
||||||
|
|
||||||
respBytes, err := json.Marshal(resp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &mcp.CallToolResult{
|
|
||||||
Content: []mcp.Content{
|
|
||||||
&mcp.TextContent{Text: string(respBytes)},
|
|
||||||
},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getLatestPosts(ctx context.Context, request *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func (s *Server) getLatestPosts(ctx context.Context, request mcp.CallToolRequest, args GetLatestPostsRequest) (*GetLatestPostsResponse, error) {
|
||||||
var args GetLatestPostsRequest
|
|
||||||
if err := json.Unmarshal(request.Params.Arguments, &args); err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid arguments: %w", err)
|
|
||||||
}
|
|
||||||
if args.Author == "" {
|
if args.Author == "" {
|
||||||
return nil, fmt.Errorf("author must be a valid did or handle")
|
return nil, fmt.Errorf("author must be a valid did or handle")
|
||||||
}
|
}
|
||||||
|
|
@ -423,28 +442,13 @@ func (s *Server) getLatestPosts(ctx context.Context, request *mcp.CallToolReques
|
||||||
if author == "" {
|
if author == "" {
|
||||||
author = args.Author
|
author = args.Author
|
||||||
}
|
}
|
||||||
resp := GetLatestPostsResponse{
|
return &GetLatestPostsResponse{
|
||||||
Author: author,
|
Author: author,
|
||||||
Posts: posts,
|
Posts: posts,
|
||||||
}
|
|
||||||
|
|
||||||
respBytes, err := json.Marshal(resp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &mcp.CallToolResult{
|
|
||||||
Content: []mcp.Content{
|
|
||||||
&mcp.TextContent{Text: string(respBytes)},
|
|
||||||
},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getPostsInTime(ctx context.Context, request *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func (s *Server) getPostsInTime(ctx context.Context, request mcp.CallToolRequest, args GetPostsInTimeRequest) (*GetPostsInTimeResponse, error) {
|
||||||
var args GetPostsInTimeRequest
|
|
||||||
if err := json.Unmarshal(request.Params.Arguments, &args); err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid arguments: %w", err)
|
|
||||||
}
|
|
||||||
if args.Author == "" {
|
if args.Author == "" {
|
||||||
return nil, fmt.Errorf("author must be a valid did or handle")
|
return nil, fmt.Errorf("author must be a valid did or handle")
|
||||||
}
|
}
|
||||||
|
|
@ -489,28 +493,13 @@ func (s *Server) getPostsInTime(ctx context.Context, request *mcp.CallToolReques
|
||||||
if author == "" {
|
if author == "" {
|
||||||
author = args.Author
|
author = args.Author
|
||||||
}
|
}
|
||||||
resp := &GetPostsInTimeResponse{
|
return &GetPostsInTimeResponse{
|
||||||
Author: author,
|
Author: author,
|
||||||
Posts: posts,
|
Posts: posts,
|
||||||
}
|
|
||||||
|
|
||||||
respBytes, err := json.Marshal(resp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &mcp.CallToolResult{
|
|
||||||
Content: []mcp.Content{
|
|
||||||
&mcp.TextContent{Text: string(respBytes)},
|
|
||||||
},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getFeed(ctx context.Context, request *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func (s *Server) getFeed(ctx context.Context, request mcp.CallToolRequest, args GetFeedRequest) (*GetFeedResponse, error) {
|
||||||
var args GetFeedRequest
|
|
||||||
if err := json.Unmarshal(request.Params.Arguments, &args); err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid arguments: %w", err)
|
|
||||||
}
|
|
||||||
if args.URI == "" {
|
if args.URI == "" {
|
||||||
return nil, fmt.Errorf("feedURI must be a valid feed URI")
|
return nil, fmt.Errorf("feedURI must be a valid feed URI")
|
||||||
}
|
}
|
||||||
|
|
@ -535,28 +524,13 @@ func (s *Server) getFeed(ctx context.Context, request *mcp.CallToolRequest) (*mc
|
||||||
CreatedAt: post.CreatedAt,
|
CreatedAt: post.CreatedAt,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
resp := GetFeedResponse{
|
return &GetFeedResponse{
|
||||||
URI: args.URI,
|
URI: args.URI,
|
||||||
Posts: posts,
|
Posts: posts,
|
||||||
}
|
|
||||||
|
|
||||||
respBytes, err := json.Marshal(resp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &mcp.CallToolResult{
|
|
||||||
Content: []mcp.Content{
|
|
||||||
&mcp.TextContent{Text: string(respBytes)},
|
|
||||||
},
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getStyleProfile(ctx context.Context, request *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
func (s *Server) getStyleProfile(ctx context.Context, request mcp.CallToolRequest, args GetStyleProfileRequest) (*GetStyleProfileResponse, error) {
|
||||||
var args GetStyleProfileRequest
|
|
||||||
if err := json.Unmarshal(request.Params.Arguments, &args); err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid arguments: %w", err)
|
|
||||||
}
|
|
||||||
if args.Author == "" {
|
if args.Author == "" {
|
||||||
return nil, fmt.Errorf("author must be a valid did or handle")
|
return nil, fmt.Errorf("author must be a valid did or handle")
|
||||||
}
|
}
|
||||||
|
|
@ -571,34 +545,15 @@ func (s *Server) getStyleProfile(ctx context.Context, request *mcp.CallToolReque
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
resp := GetStyleProfileResponse{
|
return &GetStyleProfileResponse{
|
||||||
Author: styleProfile.UserID,
|
Author: styleProfile.UserID,
|
||||||
PersonaEmbedding: embedding,
|
PersonaEmbedding: embedding,
|
||||||
TopKeywords: styleProfile.TopKeywords,
|
TopKeywords: styleProfile.TopKeywords,
|
||||||
PostCount: int(styleProfile.PostCount),
|
PostCount: int(styleProfile.PostCount),
|
||||||
StyleSummary: styleProfile.StyleSummary,
|
StyleSummary: styleProfile.StyleSummary,
|
||||||
}
|
}, err
|
||||||
|
|
||||||
respBytes, err := json.Marshal(resp)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &mcp.CallToolResult{
|
|
||||||
Content: []mcp.Content{
|
|
||||||
&mcp.TextContent{Text: string(respBytes)},
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
platform, err := determinePlatform(args.Author)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch platform {
|
|
||||||
case Bluesky:
|
|
||||||
|
|
||||||
}
|
|
||||||
res, err := s.bskyClient.GetLatestNPosts(ctx, args.Author, 50)
|
res, err := s.bskyClient.GetLatestNPosts(ctx, args.Author, 50)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -649,16 +604,16 @@ func (s *Server) getStyleProfile(ctx context.Context, request *mcp.CallToolReque
|
||||||
SourcePlatform: "bluesky",
|
SourcePlatform: "bluesky",
|
||||||
}
|
}
|
||||||
|
|
||||||
profileBytes, err := json.Marshal(profile)
|
return profile, nil
|
||||||
if err != nil {
|
}
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &mcp.CallToolResult{
|
func newUSDCPaymentRequirement(config x402go.USDCRequirementConfig, schema *x402go.OutputSchema) (x402go.PaymentRequirement, error) {
|
||||||
Content: []mcp.Content{
|
req, err := x402go.NewUSDCPaymentRequirement(config)
|
||||||
&mcp.TextContent{Text: string(profileBytes)},
|
if err != nil {
|
||||||
},
|
return x402go.PaymentRequirement{}, err
|
||||||
}, nil
|
}
|
||||||
|
req.OutputSchema = schema
|
||||||
|
return req, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func determinePlatform(author string) (platform, error) {
|
func determinePlatform(author string) (platform, error) {
|
||||||
|
|
@ -699,40 +654,6 @@ func determinePlatform(author string) (platform, error) {
|
||||||
return -1, fmt.Errorf("unknown author format: %s", author)
|
return -1, fmt.Errorf("unknown author format: %s", author)
|
||||||
}
|
}
|
||||||
|
|
||||||
func settleHook(ctx context.Context, db *store.Queries, transaction, amount, asset, network, to, from string) error {
|
|
||||||
ret, err := db.SaveTransaction(ctx, store.SaveTransactionParams{
|
|
||||||
X402TransactionHash: transaction,
|
|
||||||
Amount: amount,
|
|
||||||
Asset: asset,
|
|
||||||
Network: network,
|
|
||||||
Recipient: to,
|
|
||||||
Sender: from,
|
|
||||||
})
|
|
||||||
|
|
||||||
var id int64 = 0
|
|
||||||
if len(ret) > 0 {
|
|
||||||
id = ret[0].ID
|
|
||||||
}
|
|
||||||
|
|
||||||
fields := log.Fields{
|
|
||||||
"transaction_id": id,
|
|
||||||
"X402_transaction_hash": transaction,
|
|
||||||
"amount": amount,
|
|
||||||
"asset": asset,
|
|
||||||
"network": network,
|
|
||||||
"recipient": to,
|
|
||||||
"sender": from,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.WithFields(fields).ErrorWithContext(ctx, "Failed to save transaction", "value", ret, "error", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
log.WithFields(fields).DebugWithContext(ctx, "Saved transaction")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Server) Start() error {
|
func (s *Server) Start() error {
|
||||||
return s.mcpHandler.Start(s.listenAddress, s.permissions)
|
return s.mcpHandler.Start(s.listenAddress, s.permissions)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,18 +6,6 @@ type Bodyfield struct {
|
||||||
Required bool `json:"required,omitempty"`
|
Required bool `json:"required,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type InputSchema struct {
|
|
||||||
BodyFields map[string]any `json:"bodyFields,omitempty"`
|
|
||||||
Discoverable bool `json:"discoverable,omitempty"`
|
|
||||||
Method string `json:"method,omitempty"`
|
|
||||||
Type string `json:"type,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Schema struct {
|
|
||||||
Input InputSchema `json:"input"`
|
|
||||||
Output map[string]any `json:"output"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetLatestPostsRequest struct {
|
type GetLatestPostsRequest struct {
|
||||||
Author string `json:"author" jsonschema_description:"Did or handle of an author"`
|
Author string `json:"author" jsonschema_description:"Did or handle of an author"`
|
||||||
Limit int `json:"limit" jsonschema_description:"Number of posts to retrieve"`
|
Limit int `json:"limit" jsonschema_description:"Number of posts to retrieve"`
|
||||||
|
|
@ -84,16 +72,3 @@ type DCAPMessage struct {
|
||||||
TS int64 `json:"ts" jsonschema_description:"Unix timestamp of the message"`
|
TS int64 `json:"ts" jsonschema_description:"Unix timestamp of the message"`
|
||||||
SID string `json:"sid" jsonschema_description:"Server ID, 8-12 characters"`
|
SID string `json:"sid" jsonschema_description:"Server ID, 8-12 characters"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type platform int
|
|
||||||
|
|
||||||
const (
|
|
||||||
ActivityPub platform = iota
|
|
||||||
Bluesky
|
|
||||||
Nostr
|
|
||||||
Twitter
|
|
||||||
)
|
|
||||||
|
|
||||||
func (p platform) String() string {
|
|
||||||
return [...]string{"ActivityPub", "Bluesky", "Nostr", "Twitter"}[p]
|
|
||||||
}
|
|
||||||
|
|
|
||||||
110
internal/x402/types.go
Normal file
110
internal/x402/types.go
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
package x402
|
||||||
|
|
||||||
|
type InputSchema struct {
|
||||||
|
BodyFields map[string]any `json:"bodyFields,omitempty"`
|
||||||
|
Discoverable bool `json:"discoverable,omitempty"`
|
||||||
|
Method string `json:"method,omitempty"`
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Schema struct {
|
||||||
|
Input InputSchema `json:"input"`
|
||||||
|
Output map[string]any `json:"output"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaymentRequirement defines payment requirements for a resource/tool
|
||||||
|
// as defined in the x402 specification section 5.1
|
||||||
|
type PaymentRequirement struct {
|
||||||
|
Scheme string `json:"scheme"`
|
||||||
|
Network string `json:"network"`
|
||||||
|
MaxAmountRequired string `json:"maxAmountRequired"`
|
||||||
|
Asset string `json:"asset"`
|
||||||
|
PayTo string `json:"payTo"`
|
||||||
|
Resource string `json:"resource"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
MimeType string `json:"mimeType"`
|
||||||
|
OutputSchema Schema `json:"outputSchema"`
|
||||||
|
MaxTimeoutSeconds int `json:"maxTimeoutSeconds"`
|
||||||
|
Extra map[string]string `json:"extra,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaymentRequirements402Response is the HTTP 402 response body
|
||||||
|
type PaymentRequirements402Response struct {
|
||||||
|
X402Version int `json:"x402Version"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
Accepts []PaymentRequirement `json:"accepts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PaymentPayload represents the X-PAYMENT header content
|
||||||
|
// as defined in the x402 specification section 5.2
|
||||||
|
type PaymentPayload struct {
|
||||||
|
X402Version int `json:"x402Version"`
|
||||||
|
Scheme string `json:"scheme"`
|
||||||
|
Network string `json:"network"`
|
||||||
|
Payload struct {
|
||||||
|
Signature string `json:"signature"`
|
||||||
|
Authorization struct {
|
||||||
|
From string `json:"from"`
|
||||||
|
To string `json:"to"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
ValidAfter string `json:"validAfter"`
|
||||||
|
ValidBefore string `json:"validBefore"`
|
||||||
|
Nonce string `json:"nonce"`
|
||||||
|
} `json:"authorization"`
|
||||||
|
} `json:"payload"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettlementResponse is included in X-PAYMENT-RESPONSE header
|
||||||
|
// as defined in the x402 specification section 5.3
|
||||||
|
type SettleResponse struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
Transaction string `json:"transaction"`
|
||||||
|
Network string `json:"network"`
|
||||||
|
Payer string `json:"payer"`
|
||||||
|
ErrorReason string `json:"errorReason,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyRequest sent to facilitator /verify endpoint
|
||||||
|
// as defined in the x402 specification section 7.1
|
||||||
|
// Note: x402Version added at root level for facilitator compatibility
|
||||||
|
type VerifyRequest struct {
|
||||||
|
X402Version int `json:"x402Version"`
|
||||||
|
PaymentPayload *PaymentPayload `json:"paymentPayload"`
|
||||||
|
PaymentRequirements *PaymentRequirement `json:"paymentRequirements"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// VerifyResponse from facilitator
|
||||||
|
// as defined in the x402 specification section 7.1
|
||||||
|
type VerifyResponse struct {
|
||||||
|
IsValid bool `json:"isValid"`
|
||||||
|
Payer string `json:"payer"`
|
||||||
|
InvalidReason string `json:"invalidReason,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SettleRequest sent to facilitator /settle endpoint
|
||||||
|
// as defined in the x402 specification section 7.2
|
||||||
|
// Note: x402Version added at root level for facilitator compatibility
|
||||||
|
type SettleRequest struct {
|
||||||
|
X402Version int `json:"x402Version"`
|
||||||
|
PaymentPayload *PaymentPayload `json:"paymentPayload"`
|
||||||
|
PaymentRequirements *PaymentRequirement `json:"paymentRequirements"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config for X402Server
|
||||||
|
type Config struct {
|
||||||
|
// FacilitatorURL is the base URL of the x402 facilitator service
|
||||||
|
FacilitatorURL string
|
||||||
|
|
||||||
|
CbApiKey *string
|
||||||
|
CbApiSecret *string
|
||||||
|
// PaymentTools maps tool names to their payment requirements
|
||||||
|
// Each tool can have multiple payment options
|
||||||
|
PaymentTools map[string][]PaymentRequirement
|
||||||
|
AllTools []string
|
||||||
|
|
||||||
|
// VerifyOnly if true, only verifies but doesn't settle payments
|
||||||
|
VerifyOnly bool
|
||||||
|
|
||||||
|
// Verbose if true, logs detailed request and payment information
|
||||||
|
Verbose bool
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package x402
|
package x402
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -8,284 +10,211 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/google/jsonschema-go/jsonschema"
|
"github.com/mark3labs/mcp-go/mcp"
|
||||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
mcpserver "github.com/mark3labs/mcp-go/server"
|
||||||
|
"github.com/mark3labs/x402-go"
|
||||||
|
x402http "github.com/mark3labs/x402-go/http"
|
||||||
|
"github.com/mark3labs/x402-go/mcp/server"
|
||||||
log "github.com/nacorid/logger"
|
log "github.com/nacorid/logger"
|
||||||
x402 "github.com/x402-foundation/x402/go/v2"
|
|
||||||
x402http "github.com/x402-foundation/x402/go/v2/http"
|
|
||||||
nethttp "github.com/x402-foundation/x402/go/v2/http/nethttp"
|
|
||||||
x402mcp "github.com/x402-foundation/x402/go/v2/mcp"
|
|
||||||
evm "github.com/x402-foundation/x402/go/v2/mechanisms/evm/exact/server"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type X402Middlewares struct {
|
type X402Middlewares struct {
|
||||||
MCPMiddleware []mcp.Middleware
|
MCPMiddleware []mcpserver.ToolHandlerMiddleware
|
||||||
HTTPMiddleware []func(http.Handler) http.Handler
|
HTTPMiddleware []func(http.Handler) http.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
type ToolInfo struct {
|
type HTTPMiddleware func(http.Handler) http.Handler
|
||||||
Tool mcp.Tool
|
|
||||||
IsPayable bool
|
|
||||||
Requirements []x402.PaymentRequirements
|
|
||||||
Handler mcp.ToolHandler
|
|
||||||
}
|
|
||||||
|
|
||||||
type X402Server struct {
|
type X402Server struct {
|
||||||
mcpServer *mcp.Server
|
mcpHandler *mcpserver.MCPServer
|
||||||
x402ResourceServer *x402.X402ResourceServer
|
mcpServer *server.X402Handler
|
||||||
facilitatorClient *x402http.HTTPFacilitatorClient
|
x402Middlewares map[string]func(http.Handler) http.Handler
|
||||||
httpSettlementHook func(w http.ResponseWriter, r *http.Request, resp *x402.SettleResponse)
|
httpConfig *x402http.Config
|
||||||
mux *http.ServeMux
|
mcpConfig *server.Config
|
||||||
|
|
||||||
name string
|
toolMiddlewareChain mcpserver.ToolHandlerMiddleware
|
||||||
version string
|
middlewareChain func(http.Handler) http.Handler
|
||||||
middlewareChain func(http.Handler) http.Handler
|
AllEndpoints []string
|
||||||
tools []ToolInfo
|
Handlers map[string]mcpserver.ToolHandlerFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
const VERSION1 = "v1/"
|
func (s *X402Server) AddTool(tool mcp.Tool, handler mcpserver.ToolHandlerFunc) {
|
||||||
|
s.mcpHandler.AddTool(tool, handler)
|
||||||
func NewX402Server(name, version string, facilitatorURL string, auth x402http.AuthProvider, mws X402Middlewares, settleHook func(w http.ResponseWriter, r *http.Request, resp *x402.SettleResponse)) (*X402Server, error) {
|
s.AllEndpoints = append(s.AllEndpoints, tool.Name)
|
||||||
mcpServer := mcp.NewServer(
|
s.Handlers[tool.Name] = handler
|
||||||
&mcp.Implementation{
|
s.x402Middlewares[tool.Name] = noOpMiddleware
|
||||||
Name: name,
|
|
||||||
Version: version,
|
|
||||||
},
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
for _, mw := range mws.MCPMiddleware {
|
|
||||||
mcpServer.AddReceivingMiddleware(mw)
|
|
||||||
}
|
|
||||||
|
|
||||||
if facilitatorURL == "" {
|
|
||||||
facilitatorURL = "https://facilitator.mogami.tech"
|
|
||||||
}
|
|
||||||
facilitator := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{
|
|
||||||
URL: facilitatorURL,
|
|
||||||
AuthProvider: auth,
|
|
||||||
})
|
|
||||||
|
|
||||||
resourceServer := x402.Newx402ResourceServer(
|
|
||||||
x402.WithFacilitatorClient(facilitator),
|
|
||||||
)
|
|
||||||
|
|
||||||
resourceServer.Register("eip155:8453", evm.NewExactEvmScheme())
|
|
||||||
|
|
||||||
s := &X402Server{
|
|
||||||
mcpServer: mcpServer,
|
|
||||||
x402ResourceServer: resourceServer,
|
|
||||||
facilitatorClient: facilitator,
|
|
||||||
httpSettlementHook: settleHook,
|
|
||||||
mux: http.NewServeMux(),
|
|
||||||
name: name,
|
|
||||||
version: version,
|
|
||||||
middlewareChain: chainHTTPMiddlewares(mws.HTTPMiddleware...),
|
|
||||||
tools: make([]ToolInfo, 0),
|
|
||||||
}
|
|
||||||
|
|
||||||
s.mux.HandleFunc("GET /healthz", func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.WriteHeader(http.StatusOK)
|
|
||||||
w.Write([]byte("ok"))
|
|
||||||
})
|
|
||||||
|
|
||||||
s.mux.HandleFunc("GET /openapi.json", s.serveOpenAPI)
|
|
||||||
|
|
||||||
mcpHandler := mcp.NewStreamableHTTPHandler(func(req *http.Request) *mcp.Server {
|
|
||||||
return s.mcpServer
|
|
||||||
}, nil)
|
|
||||||
s.mux.Handle("/mcp", mcpHandler)
|
|
||||||
|
|
||||||
return s, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *X402Server) AddTool(tool mcp.Tool, handler mcp.ToolHandler) {
|
|
||||||
tool.InputSchema = toJSONSchema(tool.InputSchema)
|
|
||||||
tool.OutputSchema = toJSONSchema(tool.OutputSchema)
|
|
||||||
|
|
||||||
s.mcpServer.AddTool(&tool, handler)
|
|
||||||
|
|
||||||
s.tools = append(s.tools, ToolInfo{
|
|
||||||
Tool: tool,
|
|
||||||
IsPayable: false,
|
|
||||||
Handler: handler,
|
|
||||||
})
|
|
||||||
|
|
||||||
restHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
s.handleRESTCall(w, r, tool.Name, handler)
|
|
||||||
})
|
|
||||||
s.mux.Handle("POST /"+VERSION1+tool.Name, s.middlewareChain(restHandler))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *X402Server) AddPayableTool(
|
func (s *X402Server) AddPayableTool(
|
||||||
tool mcp.Tool,
|
tool mcp.Tool,
|
||||||
handler mcp.ToolHandler,
|
handler mcpserver.ToolHandlerFunc,
|
||||||
requirements ...x402.PaymentRequirements,
|
requirements ...x402.PaymentRequirement,
|
||||||
) {
|
) {
|
||||||
|
s.mcpHandler.AddTool(tool, handler)
|
||||||
|
|
||||||
if len(requirements) == 0 {
|
if len(requirements) == 0 {
|
||||||
log.Fatalf("tool %s requires at least one payment requirement", tool.Name)
|
log.Fatalf("tool %s requires at least one payment requirement", tool.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
tool.InputSchema = toJSONSchema(tool.InputSchema)
|
s.mcpConfig.PaymentTools[tool.Name] = requirements
|
||||||
tool.OutputSchema = toJSONSchema(tool.OutputSchema)
|
s.AllEndpoints = append(s.AllEndpoints, tool.Name)
|
||||||
|
s.Handlers[tool.Name] = handler
|
||||||
wrapper := x402mcp.NewPaymentWrapper(s.x402ResourceServer, x402mcp.PaymentWrapperConfig{
|
cfg := newMiddlewareConfig(s.httpConfig, func(c *x402http.Config) {
|
||||||
Accepts: requirements,
|
c.PaymentRequirements = requirements
|
||||||
Resource: &x402mcp.ResourceInfo{
|
|
||||||
URL: "mcp://tool/" + tool.Name,
|
|
||||||
Description: tool.Description,
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
s.x402Middlewares[tool.Name] = x402http.NewX402Middleware(&cfg)
|
||||||
s.mcpServer.AddTool(&tool, wrapper.Wrap(handler))
|
|
||||||
|
|
||||||
s.tools = append(s.tools, ToolInfo{
|
|
||||||
Tool: tool,
|
|
||||||
IsPayable: true,
|
|
||||||
Requirements: requirements,
|
|
||||||
Handler: handler,
|
|
||||||
})
|
|
||||||
|
|
||||||
var options x402http.PaymentOptions
|
|
||||||
for _, req := range requirements {
|
|
||||||
options = append(options, x402http.PaymentOption{
|
|
||||||
Scheme: req.Scheme,
|
|
||||||
PayTo: req.PayTo,
|
|
||||||
Price: req.Amount,
|
|
||||||
Network: x402.Network(req.Network),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
paymentMiddleware := nethttp.X402Payment(nethttp.Config{
|
|
||||||
Routes: x402http.RoutesConfig{
|
|
||||||
"POST /" + VERSION1 + tool.Name: {
|
|
||||||
Accepts: options,
|
|
||||||
Description: tool.Description,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Facilitator: s.facilitatorClient,
|
|
||||||
Schemes: []nethttp.SchemeConfig{
|
|
||||||
{Network: "eip155:8453", Server: evm.NewExactEvmScheme()},
|
|
||||||
},
|
|
||||||
SettlementHandler: s.httpSettlementHook,
|
|
||||||
})
|
|
||||||
|
|
||||||
restHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
s.handleRESTCall(w, r, tool.Name, handler)
|
|
||||||
})
|
|
||||||
chained := s.middlewareChain(restHandler)
|
|
||||||
s.mux.Handle("POST /"+VERSION1+tool.Name, paymentMiddleware(chained))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *X402Server) handleRESTCall(w http.ResponseWriter, r *http.Request, toolName string, handler mcp.ToolHandler) {
|
func noOpMiddleware(next http.Handler) http.Handler {
|
||||||
bodyBytes, err := io.ReadAll(r.Body)
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if err != nil {
|
next.ServeHTTP(w, r)
|
||||||
http.Error(w, "Failed to read body", http.StatusBadRequest)
|
})
|
||||||
return
|
}
|
||||||
}
|
|
||||||
|
|
||||||
log.DebugWithContext(r.Context(), "RESTful API request.", "RemoteAddr", r.RemoteAddr, "X-Forwarded-For", r.Header.Get("X-Forwarded-For"))
|
func NewX402Server(name, version string, httpConfig *x402http.Config, mws X402Middlewares) (*X402Server, error) {
|
||||||
|
toolChain := chainToolMiddlewares(mws.MCPMiddleware...)
|
||||||
|
httpChain := chainHTTPMiddlewares(mws.HTTPMiddleware...)
|
||||||
|
mcp := mcpserver.NewMCPServer(name, version,
|
||||||
|
mcpserver.WithToolHandlerMiddleware(toolChain),
|
||||||
|
mcpserver.WithRecovery(),
|
||||||
|
)
|
||||||
|
|
||||||
callReq := &mcp.CallToolRequest{
|
return &X402Server{
|
||||||
Params: &mcp.CallToolParamsRaw{
|
mcpHandler: mcp,
|
||||||
Name: toolName,
|
x402Middlewares: make(map[string]func(http.Handler) http.Handler),
|
||||||
Arguments: json.RawMessage(bodyBytes),
|
httpConfig: httpConfig,
|
||||||
|
mcpConfig: &server.Config{
|
||||||
|
FacilitatorURL: "https://facilitator.mogami.tech",
|
||||||
|
Verbose: true,
|
||||||
|
PaymentTools: make(map[string][]x402.PaymentRequirement),
|
||||||
},
|
},
|
||||||
}
|
toolMiddlewareChain: toolChain,
|
||||||
|
middlewareChain: httpChain,
|
||||||
|
Handlers: make(map[string]mcpserver.ToolHandlerFunc),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := handler(r.Context(), callReq)
|
func chainToolMiddlewares(middlewares ...mcpserver.ToolHandlerMiddleware) mcpserver.ToolHandlerMiddleware {
|
||||||
if err != nil {
|
return func(next mcpserver.ToolHandlerFunc) mcpserver.ToolHandlerFunc {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
for i := len(middlewares) - 1; i >= 0; i-- {
|
||||||
|
next = middlewares[i](next)
|
||||||
|
}
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func chainHTTPMiddlewares(middlewares ...func(http.Handler) http.Handler) func(http.Handler) http.Handler {
|
||||||
|
return func(next http.Handler) http.Handler {
|
||||||
|
for i := len(middlewares) - 1; i >= 0; i-- {
|
||||||
|
next = middlewares[i](next)
|
||||||
|
}
|
||||||
|
return next
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMiddlewareConfig(httpConfig *x402http.Config, overrides ...func(*x402http.Config)) x402http.Config {
|
||||||
|
cfg := *httpConfig
|
||||||
|
for _, override := range overrides {
|
||||||
|
override(&cfg)
|
||||||
|
}
|
||||||
|
return cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *X402Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
toolName := strings.TrimPrefix(r.URL.Path, "/")
|
||||||
|
addr := "@"
|
||||||
|
forwarded := r.Header.Get("X-Forwarded-For")
|
||||||
|
if forwarded != "" {
|
||||||
|
ip := strings.Split(forwarded, ",")[0]
|
||||||
|
addr = strings.TrimSpace(ip)
|
||||||
|
} else {
|
||||||
|
realIP := r.Header.Get("X-Real-Ip")
|
||||||
|
if realIP != "" {
|
||||||
|
addr = realIP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.InfoWithContext(r.Context(), "Request received", "host", r.Host, "method", r.Method, "path", r.URL.Path, "remoteAddr", addr)
|
||||||
|
|
||||||
|
if r.URL.Path == "/healthz" {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write([]byte("ok"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
if r.Method != http.MethodPost {
|
||||||
w.WriteHeader(http.StatusOK)
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if len(resp.Content) == 1 {
|
if handler, ok := s.Handlers[toolName]; ok {
|
||||||
if textContent, ok := resp.Content[0].(*mcp.TextContent); ok {
|
bodyBytes, err := io.ReadAll(r.Body)
|
||||||
var js json.RawMessage
|
if err != nil {
|
||||||
if json.Unmarshal([]byte(textContent.Text), &js) == nil {
|
log.WarnWithContext(r.Context(), "Failed to read request body", "error", err)
|
||||||
w.Write([]byte(textContent.Text))
|
http.Error(w, "Failed to read request body", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var args map[string]any
|
||||||
|
if len(bodyBytes) > 0 {
|
||||||
|
if err := json.Unmarshal(bodyBytes, &args); err != nil {
|
||||||
|
log.WarnWithContext(r.Context(), "Failed to parse request body as JSON", "tool", toolName, "error", err)
|
||||||
|
http.Error(w, "Invalid JSON body", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
}
|
log.DebugWithContext(r.Context(), "Empty request body for tool", "tool", toolName)
|
||||||
|
args = make(map[string]any)
|
||||||
json.NewEncoder(w).Encode(resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *X402Server) OnAfterSettle(hook func(ctx x402.SettleResultContext) error) {
|
|
||||||
s.x402ResourceServer.OnAfterSettle(hook)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *X402Server) serveOpenAPI(w http.ResponseWriter, r *http.Request) {
|
|
||||||
paths := make(map[string]any)
|
|
||||||
|
|
||||||
log.DebugWithContext(r.Context(), "OpenAPI Spec requested.", "RemoteAddr", r.RemoteAddr, "X-Forwarded-For", r.Header.Get("X-Forwarded-For"))
|
|
||||||
|
|
||||||
for _, info := range s.tools {
|
|
||||||
inputSchema := parseSchema(info.Tool.InputSchema)
|
|
||||||
outputSchema := parseSchema(info.Tool.OutputSchema)
|
|
||||||
|
|
||||||
postOp := map[string]any{
|
|
||||||
"summary": info.Tool.Description,
|
|
||||||
"description": fmt.Sprintf("Exposes the MCP tool '%s' as a RESTful endpoint.", info.Tool.Name),
|
|
||||||
"requestBody": map[string]any{
|
|
||||||
"required": true,
|
|
||||||
"content": map[string]any{
|
|
||||||
"application/json": map[string]any{
|
|
||||||
"schema": inputSchema,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"responses": map[string]any{
|
|
||||||
"200": map[string]any{
|
|
||||||
"description": "Successful operation",
|
|
||||||
"content": map[string]any{
|
|
||||||
"application/json": map[string]any{
|
|
||||||
"schema": outputSchema,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.IsPayable {
|
// Store parsed args in context
|
||||||
postOp["description"] = fmt.Sprintf("%s\n\n**Paid Route**: Requires payments via x402.", postOp["description"])
|
type contextKey string
|
||||||
postOp["responses"].(map[string]any)["402"] = map[string]any{
|
const argsKey contextKey = "parsed_args"
|
||||||
"description": "Payment Required. Responds with the PAYMENT-REQUIRED header challenge.",
|
ctx := context.WithValue(r.Context(), argsKey, args)
|
||||||
"headers": map[string]any{
|
r = r.WithContext(ctx)
|
||||||
"PAYMENT-REQUIRED": map[string]any{
|
|
||||||
"schema": map[string]any{"type": "string"},
|
r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) // Restore body for further reading
|
||||||
"description": "Base64 encoded PaymentRequired challenge matching the x402 specification.",
|
functionHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
},
|
args := r.Context().Value(argsKey).(map[string]any)
|
||||||
|
|
||||||
|
callReq := mcp.CallToolRequest{
|
||||||
|
Params: mcp.CallToolParams{
|
||||||
|
Name: toolName,
|
||||||
|
Arguments: args,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
resp, err := s.toolMiddlewareChain(handler)(r.Context(), callReq)
|
||||||
|
if err != nil {
|
||||||
|
log.WarnWithContext(r.Context(), "Tool handler error in direct handler", "tool", toolName, "error", err)
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
respBytes, err := json.Marshal(resp.Result)
|
||||||
|
if err != nil {
|
||||||
|
log.WarnWithContext(r.Context(), "Failed to marshal response", "error", err)
|
||||||
|
http.Error(w, "Failed to marshal response", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json")
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write(respBytes)
|
||||||
|
})
|
||||||
|
|
||||||
|
middleware, ok := s.x402Middlewares[toolName]
|
||||||
|
if !ok {
|
||||||
|
log.ErrorWithContext(r.Context(), "No X402 middleware found for tool", "tool", toolName)
|
||||||
|
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
s.middlewareChain(middleware(functionHandler)).ServeHTTP(w, r)
|
||||||
paths["/"+info.Tool.Name] = map[string]any{
|
} else {
|
||||||
"post": postOp,
|
http.NotFound(w, r)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
openapiDoc := map[string]any{
|
|
||||||
"openapi": "3.0.3",
|
|
||||||
"info": map[string]any{
|
|
||||||
"title": s.name,
|
|
||||||
"version": s.version,
|
|
||||||
"description": "Auto-generated REST API matching active Model Context Protocol (MCP) tools.",
|
|
||||||
},
|
|
||||||
"paths": paths,
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
_ = json.NewEncoder(w).Encode(openapiDoc)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Start starts the x402 server on the specified address
|
||||||
func (s *X402Server) Start(addr string, permissions os.FileMode) error {
|
func (s *X402Server) Start(addr string, permissions os.FileMode) error {
|
||||||
var (
|
var (
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
|
|
@ -304,8 +233,10 @@ func (s *X402Server) Start(addr string, permissions os.FileMode) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Starting X402 MCP Server on unix socket", "socketPath", socketPath)
|
log.Info("Starting X402 MCP Server on unix socket", "socketPath", socketPath)
|
||||||
|
log.Info("MCP endpoint (unix socket)", "socketPath", socketPath)
|
||||||
} else {
|
} else {
|
||||||
log.Info("Starting X402 MCP Server on TCP", "addr", addr)
|
log.Info("Starting X402 MCP Server on TCP", "addr", addr)
|
||||||
|
log.Infof("MCP endpoint: http://localhost%s", addr)
|
||||||
|
|
||||||
listener, err = net.Listen("tcp", addr)
|
listener, err = net.Listen("tcp", addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -314,76 +245,12 @@ func (s *X402Server) Start(addr string, permissions os.FileMode) error {
|
||||||
}
|
}
|
||||||
defer listener.Close()
|
defer listener.Close()
|
||||||
|
|
||||||
|
httpServer := mcpserver.NewStreamableHTTPServer(s.mcpHandler)
|
||||||
|
s.mcpServer = server.NewX402Handler(httpServer, s.mcpConfig)
|
||||||
|
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
Handler: s.mux,
|
Handler: s,
|
||||||
ErrorLog: slog.NewLogLogger(slog.Default().Handler(), slog.LevelDebug),
|
ErrorLog: slog.NewLogLogger(slog.Default().Handler(), slog.LevelDebug),
|
||||||
}
|
}
|
||||||
return srv.Serve(listener)
|
return srv.Serve(listener)
|
||||||
}
|
}
|
||||||
|
|
||||||
func toJSONSchema(val any) json.RawMessage {
|
|
||||||
if val == nil {
|
|
||||||
return json.RawMessage(`{"type": "object"}`)
|
|
||||||
}
|
|
||||||
switch v := val.(type) {
|
|
||||||
case json.RawMessage:
|
|
||||||
if len(v) == 0 {
|
|
||||||
return json.RawMessage(`{"type": "object"}`)
|
|
||||||
}
|
|
||||||
return v
|
|
||||||
case []byte:
|
|
||||||
if len(v) == 0 {
|
|
||||||
return json.RawMessage(`{"type": "object"}`)
|
|
||||||
}
|
|
||||||
return json.RawMessage(v)
|
|
||||||
case string:
|
|
||||||
if v == "" {
|
|
||||||
return json.RawMessage(`{"type": "object"}`)
|
|
||||||
}
|
|
||||||
return json.RawMessage(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
t := reflect.TypeOf(val)
|
|
||||||
schema, err := jsonschema.ForType(t, &jsonschema.ForOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return json.RawMessage(`{"type": "object"}`)
|
|
||||||
}
|
|
||||||
bytes, err := json.Marshal(schema)
|
|
||||||
if err != nil {
|
|
||||||
return json.RawMessage(`{"type": "object"}`)
|
|
||||||
}
|
|
||||||
return bytes
|
|
||||||
}
|
|
||||||
|
|
||||||
func parseSchema(schemaAny any) any {
|
|
||||||
if schemaAny == nil {
|
|
||||||
return map[string]any{"type": "object"}
|
|
||||||
}
|
|
||||||
switch v := schemaAny.(type) {
|
|
||||||
case json.RawMessage:
|
|
||||||
var m any
|
|
||||||
if err := json.Unmarshal(v, &m); err == nil {
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
case []byte:
|
|
||||||
var m any
|
|
||||||
if err := json.Unmarshal(v, &m); err == nil {
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
case string:
|
|
||||||
var m any
|
|
||||||
if err := json.Unmarshal([]byte(v), &m); err == nil {
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return schemaAny
|
|
||||||
}
|
|
||||||
|
|
||||||
func chainHTTPMiddlewares(middlewares ...func(http.Handler) http.Handler) func(http.Handler) http.Handler {
|
|
||||||
return func(next http.Handler) http.Handler {
|
|
||||||
for i := len(middlewares) - 1; i >= 0; i-- {
|
|
||||||
next = middlewares[i](next)
|
|
||||||
}
|
|
||||||
return next
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,206 +0,0 @@
|
||||||
package x402
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
"net/http/httptest"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
|
||||||
x402 "github.com/x402-foundation/x402/go/v2"
|
|
||||||
x402http "github.com/x402-foundation/x402/go/v2/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DummyAuthProvider struct{}
|
|
||||||
|
|
||||||
func (d *DummyAuthProvider) GetAuthHeaders(ctx context.Context) (x402http.AuthHeaders, error) {
|
|
||||||
return x402http.AuthHeaders{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestX402Server_HTTPBoundaries(t *testing.T) {
|
|
||||||
mockFacilitator := setupMockFacilitator()
|
|
||||||
defer mockFacilitator.Close()
|
|
||||||
|
|
||||||
srv, err := NewX402Server(
|
|
||||||
"Test Agent API",
|
|
||||||
"1.0.0",
|
|
||||||
mockFacilitator.URL,
|
|
||||||
&DummyAuthProvider{},
|
|
||||||
X402Middlewares{},
|
|
||||||
func(w http.ResponseWriter, r *http.Request, resp *x402.SettleResponse) {},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to create server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
srv.AddPayableTool(
|
|
||||||
mcp.Tool{
|
|
||||||
Name: "getTestPost",
|
|
||||||
Description: "Gated test endpoint",
|
|
||||||
},
|
|
||||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
||||||
return &mcp.CallToolResult{
|
|
||||||
Content: []mcp.Content{&mcp.TextContent{Text: `{"status": "success"}`}},
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
x402.PaymentRequirements{
|
|
||||||
Scheme: "exact",
|
|
||||||
Network: "eip155:8453",
|
|
||||||
Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
||||||
Amount: "1000",
|
|
||||||
PayTo: "0x0000000000000000000000000000000000000000",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
reqRec := httptest.NewRecorder()
|
|
||||||
reqHealth, _ := http.NewRequest("GET", "/healthz", nil)
|
|
||||||
srv.mux.ServeHTTP(reqRec, reqHealth)
|
|
||||||
if reqRec.Code != http.StatusOK {
|
|
||||||
t.Errorf("expected healthz status 200, got %d", reqRec.Code)
|
|
||||||
}
|
|
||||||
|
|
||||||
reqRecOpenAPI := httptest.NewRecorder()
|
|
||||||
reqOpenAPI, _ := http.NewRequest("GET", "/openapi.json", nil)
|
|
||||||
srv.mux.ServeHTTP(reqRecOpenAPI, reqOpenAPI)
|
|
||||||
if reqRecOpenAPI.Code != http.StatusOK {
|
|
||||||
t.Errorf("expected OpenAPI status 200, got %d", reqRecOpenAPI.Code)
|
|
||||||
}
|
|
||||||
if !strings.Contains(reqRecOpenAPI.Body.String(), "getTestPost") {
|
|
||||||
t.Error("OpenAPI spec did not render registered tool definitions")
|
|
||||||
}
|
|
||||||
|
|
||||||
reqRecPayable := httptest.NewRecorder()
|
|
||||||
reqPayable, _ := http.NewRequest("POST", "/v1/getTestPost", strings.NewReader(`{}`))
|
|
||||||
srv.mux.ServeHTTP(reqRecPayable, reqPayable)
|
|
||||||
|
|
||||||
if reqRecPayable.Code != http.StatusPaymentRequired {
|
|
||||||
t.Errorf("expected status 402 (Payment Required), got %d", reqRecPayable.Code)
|
|
||||||
}
|
|
||||||
|
|
||||||
payHeader := reqRecPayable.Header().Get("PAYMENT-REQUIRED")
|
|
||||||
if payHeader == "" {
|
|
||||||
t.Error("missing PAYMENT-REQUIRED response header on 402 challenge")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestX402Server_MCPBoundaries(t *testing.T) {
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
serverTransport, clientTransport := mcp.NewInMemoryTransports()
|
|
||||||
|
|
||||||
mockFacilitator := setupMockFacilitator()
|
|
||||||
defer mockFacilitator.Close()
|
|
||||||
|
|
||||||
srv, err := NewX402Server(
|
|
||||||
"Test Agent API",
|
|
||||||
"1.0.0",
|
|
||||||
mockFacilitator.URL,
|
|
||||||
&DummyAuthProvider{},
|
|
||||||
X402Middlewares{},
|
|
||||||
func(w http.ResponseWriter, r *http.Request, resp *x402.SettleResponse) {},
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to create server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
srv.AddPayableTool(
|
|
||||||
mcp.Tool{
|
|
||||||
Name: "getTestPost",
|
|
||||||
Description: "Gated test endpoint",
|
|
||||||
},
|
|
||||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
|
||||||
return &mcp.CallToolResult{
|
|
||||||
Content: []mcp.Content{&mcp.TextContent{Text: `{"status": "success"}`}},
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
x402.PaymentRequirements{
|
|
||||||
Scheme: "exact",
|
|
||||||
Network: "eip155:8453",
|
|
||||||
Asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
|
|
||||||
Amount: "1000",
|
|
||||||
PayTo: "0x0000000000000000000000000000000000000000",
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
serverSession, err := srv.mcpServer.Connect(ctx, serverTransport, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to connect server session: %v", err)
|
|
||||||
}
|
|
||||||
defer serverSession.Close()
|
|
||||||
|
|
||||||
client := mcp.NewClient(&mcp.Implementation{Name: "test-client", Version: "1.0.0"}, nil)
|
|
||||||
clientSession, err := client.Connect(ctx, clientTransport, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to connect client session: %v", err)
|
|
||||||
}
|
|
||||||
defer clientSession.Close()
|
|
||||||
|
|
||||||
toolsResponse, err := clientSession.ListTools(ctx, nil)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("failed to list tools over MCP: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
found := false
|
|
||||||
for _, tool := range toolsResponse.Tools {
|
|
||||||
if tool.Name == "getTestPost" {
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !found {
|
|
||||||
t.Error("expected tool 'getTestPost' to be discovered by the MCP client, but it was missing")
|
|
||||||
}
|
|
||||||
|
|
||||||
result, err := clientSession.CallTool(ctx, &mcp.CallToolParams{
|
|
||||||
Name: "getTestPost",
|
|
||||||
Arguments: json.RawMessage(`{}`),
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Unexpected protocol-level error: %v", err)
|
|
||||||
} else {
|
|
||||||
if !result.IsError {
|
|
||||||
t.Error("expected CallTool to return a payment challenge, but it returned a successful, free result")
|
|
||||||
} else {
|
|
||||||
t.Logf("Intercepted expected application-level payment challenge.")
|
|
||||||
t.Logf("Content: %v", result.Content)
|
|
||||||
t.Logf("Meta fields: %v", result.Meta)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupMockFacilitator() *httptest.Server {
|
|
||||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case r.Method == "GET" && r.URL.Path == "/supported":
|
|
||||||
_, _ = w.Write([]byte(`{
|
|
||||||
"kinds": [
|
|
||||||
{
|
|
||||||
"x402Version": 2,
|
|
||||||
"scheme": "exact",
|
|
||||||
"network": "eip155:8453"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}`))
|
|
||||||
case r.Method == "POST" && r.URL.Path == "/verify":
|
|
||||||
_, _ = w.Write([]byte(`{
|
|
||||||
"isValid": true,
|
|
||||||
"invalidReason": ""
|
|
||||||
}`))
|
|
||||||
case r.Method == "POST" && r.URL.Path == "/settle":
|
|
||||||
_, _ = w.Write([]byte(`{
|
|
||||||
"success": true,
|
|
||||||
"transaction": "0x1234abcd",
|
|
||||||
"network": "eip155:8453",
|
|
||||||
"payer": "0xabcd1234"
|
|
||||||
}`))
|
|
||||||
default:
|
|
||||||
w.WriteHeader(http.StatusNotFound)
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
|
|
@ -4,13 +4,12 @@ After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
User=mcpserver
|
User=mcpserver
|
||||||
Group=mcpserver
|
Group=www-data
|
||||||
|
|
||||||
WorkingDirectory=/home/ubuntu/gitSources/mcpServer
|
WorkingDirectory=/home/ubuntu/gitSources/mcpServer
|
||||||
ExecStart=/home/ubuntu/gitSources/mcpServer/bin/main
|
ExecStart=/home/ubuntu/gitSources/mcpServer/bin/main
|
||||||
|
|
||||||
RuntimeDirectory=mcpserver
|
RuntimeDirectory=mcpserver
|
||||||
RuntimeDirectoryMode=0750
|
|
||||||
|
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=3s
|
RestartSec=3s
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue