diff --git a/.golangci.yaml b/.golangci.yaml index 5a4a7bd2a..8ce111896 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -5,6 +5,8 @@ linters: checks: - all - -QF1003 # "could use tagged switch" + - -ST1003 # "should not use underscores in Go names" - indigo's code gen makes some + - -SA5008 # "unknown JSON option" doesn't care for the const stuff disable: - unused exclusions: diff --git a/Makefile b/Makefile index d3dc1d2ea..511107201 100644 --- a/Makefile +++ b/Makefile @@ -130,6 +130,7 @@ js-lexicons: && sed -i.bak 's/PlaceStreamChatProfile\.Main/PlaceStreamChatProfile\.Record/' $$(find ./js/streamplace/src/lexicons/types/place/stream -type f) \ && sed -i.bak "s/import\ \*\ as\ AppBskyFeedDefs\ from\ '.\/defs'/import \{ AppBskyFeedDefs } from '@atproto\/api'/" $$(find ./js/streamplace/src/lexicons/types -type f) \ && sed -i.bak "s/import\ \*\ as\ AppBskyActorDefs\ from\ '.\/defs'/import \{ AppBskyActorDefs } from '@atproto\/api'/" $$(find ./js/streamplace/src/lexicons -type f) \ + && npx prettier --write $$(find ./js/streamplace/src/lexicons -type f -name '*.ts') \ && find . | grep bak$$ | xargs rm .PHONY: md-lexicons diff --git a/go.mod b/go.mod index cf188a6d6..c171ff264 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/NYTimes/gziphandler v1.1.1 github.com/ThalesGroup/crypto11 v0.0.0-00010101000000-000000000000 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d - github.com/bluesky-social/indigo v0.0.0-20250520232546-236dd575c91e + github.com/bluesky-social/indigo v0.0.0-20250617211950-336ebe49427b github.com/cenkalti/backoff/v5 v5.0.2 github.com/decred/dcrd/dcrec/secp256k1 v1.0.4 github.com/dunglas/httpsfv v1.0.2 @@ -31,7 +31,9 @@ require ( github.com/golangci/golangci-lint/v2 v2.1.6 github.com/google/uuid v1.6.0 github.com/gorilla/websocket v1.5.3 - github.com/ipfs/go-cid v0.4.1 + github.com/ipfs/go-cid v0.5.0 + github.com/ipfs/go-ipld-cbor v0.2.0 + github.com/ipld/go-car v0.6.1-0.20230509095817-92d28eb23ba4 github.com/johncgriffin/overflow v0.0.0-20211019200055-46fa312c352c github.com/julienschmidt/httprouter v1.3.0 github.com/labstack/echo/v4 v4.13.3 @@ -43,31 +45,31 @@ require ( github.com/orandin/slog-gorm v1.4.0 github.com/peterbourgon/ff/v3 v3.4.0 github.com/pion/interceptor v0.1.37 - github.com/pion/rtcp v1.2.14 - github.com/pion/webrtc/v4 v4.0.5 + github.com/pion/rtcp v1.2.15 + github.com/pion/webrtc/v4 v4.0.10 github.com/piprate/json-gold v0.5.0 - github.com/prometheus/client_golang v1.20.3 + github.com/prometheus/client_golang v1.22.0 github.com/rs/cors v1.7.0 github.com/samber/slog-http v1.4.0 github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/slok/go-http-metrics v0.13.0 - github.com/streamplace/atproto-oauth-golang v0.0.0-20250521042753-9cfa9e504155 - github.com/streamplace/oatproxy v0.0.0-20250531005031-5c1979905fdc + github.com/streamplace/atproto-oauth-golang v0.0.0-20250619231223-a9c04fb888ac + github.com/streamplace/oatproxy v0.0.0-20250619231549-b15df1b82a3a github.com/stretchr/testify v1.10.0 - github.com/whyrusleeping/cbor-gen v0.2.1-0.20241030202151-b7a6831be65e + github.com/whyrusleeping/cbor-gen v0.3.1 + github.com/whyrusleeping/go-did v0.0.0-20230824162731-404d1707d5d6 gitlab.com/gitlab-org/release-cli v0.18.0 - go.opentelemetry.io/otel v1.35.0 + go.opentelemetry.io/otel v1.36.0 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 - go.opentelemetry.io/otel/sdk v1.35.0 - go.opentelemetry.io/otel/trace v1.35.0 - golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 + go.opentelemetry.io/otel/sdk v1.36.0 + go.opentelemetry.io/otel/trace v1.36.0 golang.org/x/image v0.22.0 - golang.org/x/net v0.39.0 - golang.org/x/sync v0.13.0 - golang.org/x/term v0.31.0 + golang.org/x/net v0.41.0 + golang.org/x/sync v0.15.0 + golang.org/x/term v0.32.0 golang.org/x/time v0.11.0 - golang.org/x/tools v0.32.0 - golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 + golang.org/x/tools v0.34.0 + golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da google.golang.org/api v0.228.0 gorm.io/datatypes v1.2.4 gorm.io/driver/sqlite v1.5.7 @@ -77,7 +79,7 @@ require ( github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/mattn/go-isatty v0.0.20 - golang.org/x/sys v0.32.0 // indirect + golang.org/x/sys v0.33.0 // indirect gorm.io/gorm v1.26.1 ) @@ -176,7 +178,7 @@ require ( github.com/go-critic/go-critic v0.13.0 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-toolsmith/astcast v1.1.0 // indirect @@ -189,7 +191,7 @@ require ( github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect github.com/gobwas/glob v0.2.3 // indirect - github.com/goccy/go-json v0.10.3 // indirect + github.com/goccy/go-json v0.10.5 // indirect github.com/gocql/gocql v1.7.0 // indirect github.com/gofrs/flock v0.12.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -221,7 +223,7 @@ require ( github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect - github.com/hashicorp/go-retryablehttp v0.7.5 // indirect + github.com/hashicorp/go-retryablehttp v0.7.8 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect @@ -230,31 +232,29 @@ require ( github.com/holiman/uint256 v1.3.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/ipfs/bbloom v0.0.4 // indirect - github.com/ipfs/go-block-format v0.2.0 // indirect + github.com/ipfs/boxo v0.32.0 // indirect + github.com/ipfs/go-block-format v0.2.1 // indirect github.com/ipfs/go-blockservice v0.5.2 // indirect - github.com/ipfs/go-datastore v0.6.0 // indirect + github.com/ipfs/go-datastore v0.8.2 // indirect github.com/ipfs/go-ipfs-blockstore v1.3.1 // indirect github.com/ipfs/go-ipfs-ds-help v1.1.1 // indirect github.com/ipfs/go-ipfs-exchange-interface v0.2.1 // indirect github.com/ipfs/go-ipfs-util v0.0.3 // indirect - github.com/ipfs/go-ipld-cbor v0.1.0 // indirect - github.com/ipfs/go-ipld-format v0.6.0 // indirect + github.com/ipfs/go-ipld-format v0.6.1 // indirect github.com/ipfs/go-ipld-legacy v0.2.1 // indirect github.com/ipfs/go-libipfs v0.7.0 // indirect github.com/ipfs/go-log v1.0.5 // indirect - github.com/ipfs/go-log/v2 v2.5.1 // indirect + github.com/ipfs/go-log/v2 v2.6.0 // indirect github.com/ipfs/go-merkledag v0.11.0 // indirect - github.com/ipfs/go-metrics-interface v0.0.1 // indirect + github.com/ipfs/go-metrics-interface v0.3.0 // indirect github.com/ipfs/go-verifcid v0.0.3 // indirect - github.com/ipld/go-car v0.6.1-0.20230509095817-92d28eb23ba4 // indirect - github.com/ipld/go-codec-dagpb v1.6.0 // indirect + github.com/ipld/go-codec-dagpb v1.7.0 // indirect github.com/ipld/go-ipld-prime v0.21.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect github.com/jackc/pgx/v5 v5.5.5 // indirect github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect - github.com/jbenet/goprocess v0.1.4 // indirect github.com/jgautheron/goconst v1.8.1 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect github.com/jjti/go-spancheck v0.6.4 // indirect @@ -264,8 +264,7 @@ require ( github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/kisielk/errcheck v1.9.0 // indirect github.com/kkHAIKE/contextcheck v1.1.6 // indirect - github.com/klauspost/compress v1.17.9 // indirect - github.com/klauspost/cpuid/v2 v2.2.8 // indirect + github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/kulti/thelper v0.6.3 // indirect github.com/kunwardeep/paralleltest v1.0.14 // indirect github.com/labstack/gommon v0.4.2 // indirect @@ -276,7 +275,7 @@ require ( github.com/ldez/tagliatelle v0.7.1 // indirect github.com/ldez/usetesting v0.4.3 // indirect github.com/leonklingele/grouper v1.1.2 // indirect - github.com/lestrrat-go/blackmagic v1.0.3 // indirect + github.com/lestrrat-go/blackmagic v1.0.4 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httprc v1.0.6 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect @@ -315,15 +314,15 @@ require ( github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect - github.com/pion/datachannel v1.5.9 // indirect + github.com/pion/datachannel v1.5.10 // indirect github.com/pion/dtls/v3 v3.0.4 // indirect - github.com/pion/ice/v4 v4.0.3 // indirect - github.com/pion/logging v0.2.2 // indirect + github.com/pion/ice/v4 v4.0.8 // indirect + github.com/pion/logging v0.2.3 // indirect github.com/pion/mdns/v2 v2.0.7 // indirect github.com/pion/randutil v0.1.0 // indirect - github.com/pion/rtp v1.8.9 // indirect - github.com/pion/sctp v1.8.34 // indirect - github.com/pion/sdp/v3 v3.0.9 // indirect + github.com/pion/rtp v1.8.11 // indirect + github.com/pion/sctp v1.8.37 // indirect + github.com/pion/sdp/v3 v3.0.10 // indirect github.com/pion/srtp/v3 v3.0.4 // indirect github.com/pion/stun/v3 v3.0.0 // indirect github.com/pion/transport/v3 v3.0.7 // indirect @@ -333,9 +332,9 @@ require ( github.com/polydawn/refmt v0.89.1-0.20221221234430-40501e09de1f // indirect github.com/polyfloyd/go-errorlint v1.8.0 // indirect github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.59.1 // indirect - github.com/prometheus/procfs v0.15.1 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.63.0 // indirect + github.com/prometheus/procfs v0.16.1 // indirect github.com/quasilyte/go-ruleguard v0.4.4 // indirect github.com/quasilyte/go-ruleguard/dsl v0.3.22 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect @@ -405,20 +404,20 @@ require ( go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect - go.opentelemetry.io/otel/metric v1.35.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.36.0 // indirect go.opentelemetry.io/proto/otlp v1.5.0 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.26.0 // indirect - golang.org/x/crypto v0.37.0 // indirect + go.uber.org/zap v1.27.0 // indirect + golang.org/x/crypto v0.39.0 // indirect + golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect - golang.org/x/mod v0.24.0 // indirect + golang.org/x/mod v0.25.0 // indirect golang.org/x/oauth2 v0.28.0 // indirect - golang.org/x/text v0.24.0 // indirect + golang.org/x/text v0.26.0 // indirect google.golang.org/appengine/v2 v2.0.2 // indirect google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect @@ -432,7 +431,7 @@ require ( gorm.io/driver/mysql v1.5.6 // indirect gorm.io/driver/postgres v1.5.7 // indirect honnef.co/go/tools v0.6.1 // indirect - lukechampine.com/blake3 v1.2.1 // indirect + lukechampine.com/blake3 v1.4.1 // indirect mvdan.cc/gofumpt v0.8.0 // indirect mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 // indirect rsc.io/tmplfunc v0.0.3 // indirect diff --git a/go.sum b/go.sum index d575e7a9d..a620fb41f 100644 --- a/go.sum +++ b/go.sum @@ -107,9 +107,8 @@ github.com/ashanbrown/makezero v1.2.0 h1:/2Lp1bypdmK9wDIq7uWBlDF1iMUpIIS4A+pF6C9 github.com/ashanbrown/makezero v1.2.0/go.mod h1:dxlPhHbDMC6N6xICzFBSK+4njQDdK8euNO0qjQMtGY4= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +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/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932 h1:mXoPYz/Ul5HYEDvkta6I8/rnYM5gSdSV2tJ6XbZuEtY= @@ -120,8 +119,8 @@ github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5 github.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo= github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= -github.com/bluesky-social/indigo v0.0.0-20250520232546-236dd575c91e h1:DVD+HxQsDCVJtAkjfIKZVaBNc3kayHaU+A2TJZkFdp4= -github.com/bluesky-social/indigo v0.0.0-20250520232546-236dd575c91e/go.mod h1:ovyxp8AMO1Hoe838vMJUbqHTZaAR8ABM3g3TXu+A5Ng= +github.com/bluesky-social/indigo v0.0.0-20250617211950-336ebe49427b h1:qc08nIOSRS3Ue5rqRjI3SgxBPS30QvGkBrMoV2+z2KA= +github.com/bluesky-social/indigo v0.0.0-20250617211950-336ebe49427b/go.mod h1:8FlFpF5cIq3DQG0kEHqyTkPV/5MDQoaWLcVwza5ZPJU= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ= @@ -214,6 +213,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= +github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/chaincfg/chainhash v1.0.2 h1:rt5Vlq/jM3ZawwiacWjPa+smINyLRN07EO0cNBV6DGU= @@ -257,8 +258,14 @@ github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4 github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/filecoin-project/go-clock v0.1.0 h1:SFbYIM75M8NnFm1yMHhN9Ahy3W5bEZV9gd6MPfXbKVU= +github.com/filecoin-project/go-clock v0.1.0/go.mod h1:4uB/O4PvOjlx1VCMdZ9MyDZXRm//gkj1ELEbxfI1AZs= github.com/firefart/nonamedreturns v1.0.6 h1:vmiBcKV/3EqKY3ZiPxCINmpS431OcE1S47AQUwhrg8E= github.com/firefart/nonamedreturns v1.0.6/go.mod h1:R8NisJnSIpvPWheCq0mNRXJok6D8h7fagJTF8EMEwCo= +github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= +github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= +github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= +github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= 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.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= @@ -288,8 +295,8 @@ github.com/go-gst/go-glib v1.4.0/go.mod h1:GUIpWmkxQ1/eL+FYSjKpLDyTZx6Vgd9nNXt8d github.com/go-gst/go-gst v1.4.0 h1:EikB43u4c3wc8d2RzlFRSfIGIXYzDy6Zls2vJqrG2BU= github.com/go-gst/go-gst v1.4.0/go.mod h1:p8TLGtOxJLcrp6PCkTPdnanwWBxPZvYiHDbuSuwgO3c= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 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-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= @@ -329,8 +336,8 @@ github.com/go-xmlfmt/xmlfmt v1.1.3/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6C github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= -github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= +github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -405,8 +412,8 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= -github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/google/pprof v0.0.0-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc= +github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0= github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM= @@ -418,8 +425,9 @@ github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA= github.com/googleapis/gax-go/v2 v2.14.1 h1:hb0FFeiPaQskmvakKu5EbCbpntQn48jyHuvrkurSS/Q= github.com/googleapis/gax-go/v2 v2.14.1/go.mod h1:Hb/NubMaVM88SrNkvl8X/o8XWwDJEPqouaLeN2IUxoA= -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-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gordonklaus/ineffassign v0.1.0 h1:y2Gd/9I7MdY1oEIt+n+rowjBNDcLQq3RsH5hwJd0f9s= github.com/gordonklaus/ineffassign v0.1.0/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0= github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= @@ -446,15 +454,14 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 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-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= -github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix/v2 v2.1.0 h1:CUW5RYIcysz+D3B+l1mDeXrQ7fUvGGCwJfdASSzbrfo= github.com/hashicorp/go-immutable-radix/v2 v2.1.0/go.mod h1:hgdqLXA4f6NIjRVisM1TJ9aOJVNRqKZj+xDGF6m7PBw= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= -github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= +github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -477,18 +484,20 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 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/boxo v0.32.0 h1:rBs3P53Wt9bFW9WJwVdkzLtzYCXAj2bMjM7+1nrazZw= +github.com/ipfs/boxo v0.32.0/go.mod h1:VEtO3gOmr+sXGodalaTV9Vvsp3qVYegc4Rcu08Iw+wM= github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ= github.com/ipfs/go-bitswap v0.11.0/go.mod h1:05aE8H3XOU+LXpTedeAS0OZpcO1WFsj5niYQH9a1Tmk= -github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= -github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= +github.com/ipfs/go-block-format v0.2.1 h1:96kW71XGNNa+mZw/MTzJrCpMhBWCrd9kBLoKm9Iip/Q= +github.com/ipfs/go-block-format v0.2.1/go.mod h1:frtvXHMQhM6zn7HvEQu+Qz5wSTj+04oEH/I+NjDgEjk= github.com/ipfs/go-blockservice v0.5.2 h1:in9Bc+QcXwd1apOVM7Un9t8tixPKdaHQFdLSUM1Xgk8= github.com/ipfs/go-blockservice v0.5.2/go.mod h1:VpMblFEqG67A/H2sHKAemeH9vlURVavlysbdUI632yk= github.com/ipfs/go-bs-sqlite3 v0.0.0-20221122195556-bfcee1be620d h1:9V+GGXCuOfDiFpdAHz58q9mKLg447xp0cQKvqQrAwYE= github.com/ipfs/go-bs-sqlite3 v0.0.0-20221122195556-bfcee1be620d/go.mod h1:pMbnFyNAGjryYCLCe59YDLRv/ujdN+zGJBT1umlvYRM= -github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= -github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= -github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= -github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= +github.com/ipfs/go-cid v0.5.0 h1:goEKKhaGm0ul11IHA7I6p1GmKz8kEYniqFopaB5Otwg= +github.com/ipfs/go-cid v0.5.0/go.mod h1:0L7vmeNXpQpUS9vt+yEARkJ8rOg43DF3iPgn4GIN0mk= +github.com/ipfs/go-datastore v0.8.2 h1:Jy3wjqQR6sg/LhyY0NIePZC3Vux19nLtg7dx0TVqr6U= +github.com/ipfs/go-datastore v0.8.2/go.mod h1:W+pI1NsUsz3tcsAACMtfC+IZdnQTnC/7VfPoJBQuts0= github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ds-flatfs v0.5.1 h1:ZCIO/kQOS/PSh3vcF1H6a8fkRGS7pOfwfPdx4n/KJH4= @@ -511,10 +520,10 @@ github.com/ipfs/go-ipfs-routing v0.3.0 h1:9W/W3N+g+y4ZDeffSgqhgo7BsBSJwPMcyssET9 github.com/ipfs/go-ipfs-routing v0.3.0/go.mod h1:dKqtTFIql7e1zYsEuWLyuOU+E0WJWW8JjbTPLParDWo= github.com/ipfs/go-ipfs-util v0.0.3 h1:2RFdGez6bu2ZlZdI+rWfIdbQb1KudQp3VGwPtdNCmE0= github.com/ipfs/go-ipfs-util v0.0.3/go.mod h1:LHzG1a0Ig4G+iZ26UUOMjHd+lfM84LZCrn17xAKWBvs= -github.com/ipfs/go-ipld-cbor v0.1.0 h1:dx0nS0kILVivGhfWuB6dUpMa/LAwElHPw1yOGYopoYs= -github.com/ipfs/go-ipld-cbor v0.1.0/go.mod h1:U2aYlmVrJr2wsUBU67K4KgepApSZddGRDWBYR0H4sCk= -github.com/ipfs/go-ipld-format v0.6.0 h1:VEJlA2kQ3LqFSIm5Vu6eIlSxD/Ze90xtc4Meten1F5U= -github.com/ipfs/go-ipld-format v0.6.0/go.mod h1:g4QVMTn3marU3qXchwjpKPKgJv+zF+OlaKMyhJ4LHPg= +github.com/ipfs/go-ipld-cbor v0.2.0 h1:VHIW3HVIjcMd8m4ZLZbrYpwjzqlVUfjLM7oK4T5/YF0= +github.com/ipfs/go-ipld-cbor v0.2.0/go.mod h1:Cp8T7w1NKcu4AQJLqK0tWpd1nkgTxEVB5C6kVpLW6/0= +github.com/ipfs/go-ipld-format v0.6.1 h1:lQLmBM/HHbrXvjIkrydRXkn+gc0DE5xO5fqelsCKYOQ= +github.com/ipfs/go-ipld-format v0.6.1/go.mod h1:8TOH1Hj+LFyqM2PjSqI2/ZnyO0KlfhHbJLkbxFa61hs= github.com/ipfs/go-ipld-legacy v0.2.1 h1:mDFtrBpmU7b//LzLSypVrXsD8QxkEWxu5qVxN99/+tk= github.com/ipfs/go-ipld-legacy v0.2.1/go.mod h1:782MOUghNzMO2DER0FlBR94mllfdCJCkTtDtPM51otM= github.com/ipfs/go-libipfs v0.7.0 h1:Mi54WJTODaOL2/ZSm5loi3SwI3jI2OuFWUrQIkJ5cpM= @@ -522,22 +531,22 @@ github.com/ipfs/go-libipfs v0.7.0/go.mod h1:KsIf/03CqhICzyRGyGo68tooiBE2iFbI/rXW github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= -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.6.0 h1:2Nu1KKQQ2ayonKp4MPo6pXCjqw1ULc9iohRqWV5EYqg= +github.com/ipfs/go-log/v2 v2.6.0/go.mod h1:p+Efr3qaY5YXpx9TX7MoLCSEZX5boSWj9wh86P5HJa8= github.com/ipfs/go-merkledag v0.11.0 h1:DgzwK5hprESOzS4O1t/wi6JDpyVQdvm9Bs59N/jqfBY= github.com/ipfs/go-merkledag v0.11.0/go.mod h1:Q4f/1ezvBiJV0YCIXvt51W/9/kqJGH4I1LsA7+djsM4= -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-peertaskqueue v0.8.1 h1:YhxAs1+wxb5jk7RvS0LHdyiILpNmRIRnZVztekOF0pg= -github.com/ipfs/go-peertaskqueue v0.8.1/go.mod h1:Oxxd3eaK279FxeydSPPVGHzbwVeHjatZ2GA8XD+KbPU= +github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU= +github.com/ipfs/go-metrics-interface v0.3.0/go.mod h1:OxxQjZDGocXVdyTPocns6cOLwHieqej/jos7H4POwoY= +github.com/ipfs/go-peertaskqueue v0.8.2 h1:PaHFRaVFdxQk1Qo3OKiHPYjmmusQy7gKQUaL8JDszAU= +github.com/ipfs/go-peertaskqueue v0.8.2/go.mod h1:L6QPvou0346c2qPJNiJa6BvOibxDfaiPlqHInmzg0FA= github.com/ipfs/go-verifcid v0.0.3 h1:gmRKccqhWDocCRkC+a59g5QW7uJw5bpX9HWBevXa0zs= github.com/ipfs/go-verifcid v0.0.3/go.mod h1:gcCtGniVzelKrbk9ooUSX/pM3xlH73fZZJDzQJRvOUw= github.com/ipld/go-car v0.6.1-0.20230509095817-92d28eb23ba4 h1:oFo19cBmcP0Cmg3XXbrr0V/c+xU9U1huEZp8+OgBzdI= github.com/ipld/go-car v0.6.1-0.20230509095817-92d28eb23ba4/go.mod h1:6nkFF8OmR5wLKBzRKi7/YFJpyYR7+oEn1DX+mMWnlLA= -github.com/ipld/go-car/v2 v2.13.1 h1:KnlrKvEPEzr5IZHKTXLAEub+tPrzeAFQVRlSQvuxBO4= -github.com/ipld/go-car/v2 v2.13.1/go.mod h1:QkdjjFNGit2GIkpQ953KBwowuoukoM75nP/JI1iDJdo= -github.com/ipld/go-codec-dagpb v1.6.0 h1:9nYazfyu9B1p3NAgfVdpRco3Fs2nFC72DqVsMj6rOcc= -github.com/ipld/go-codec-dagpb v1.6.0/go.mod h1:ANzFhfP2uMJxRBr8CE+WQWs5UsNa0pYtmKZ+agnUw9s= +github.com/ipld/go-car/v2 v2.14.3 h1:1Mhl82/ny8MVP+w1M4LXbj4j99oK3gnuZG2GmG1IhC8= +github.com/ipld/go-car/v2 v2.14.3/go.mod h1:/vpSvPngOX8UnvmdFJ3o/mDgXa9LuyXsn7wxOzHDYQE= +github.com/ipld/go-codec-dagpb v1.7.0 h1:hpuvQjCSVSLnTnHXn+QAMR0mLmb1gA6wl10LExo2Ts0= +github.com/ipld/go-codec-dagpb v1.7.0/go.mod h1:rD3Zg+zub9ZnxcLwfol/OTQRVjaLzXypgy4UqHQvilM= github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E= github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -550,9 +559,10 @@ github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= 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-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= +github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= +github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= github.com/jgautheron/goconst v1.8.1 h1:PPqCYp3K/xlOj5JmIe6O1Mj6r1DbkdbLtR3AJuZo414= @@ -587,12 +597,12 @@ github.com/kisielk/errcheck v1.9.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkHAIKE/contextcheck v1.1.6 h1:7HIyRcnyzxL9Lz06NGhiKvenXq7Zw6Q0UQu/ttjfJCE= github.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= -github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/koron/go-ssdp v0.0.3 h1:JivLMY45N76b4p/vsWGOKewBQu6uf39y8l+AQ7sDKx8= -github.com/koron/go-ssdp v0.0.3/go.mod h1:b2MxI6yh02pKrsyNoQUsk4+YNikaGhe4894J+Q5lDvA= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= +github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/koron/go-ssdp v0.0.5 h1:E1iSMxIs4WqxTbIBLtmNBeOOC+1sCIXQeqTWVnpmwhk= +github.com/koron/go-ssdp v0.0.5/go.mod h1:Qm59B7hpKpDqfyRNWRNr00jGwLdXjDyZh6y7rH6VS0w= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -626,8 +636,8 @@ github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7 github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= github.com/leonklingele/grouper v1.1.2/go.mod h1:6D0M/HVkhs2yRKRFZUoGjeDy7EZTfFBE9gl4kjmIGkA= -github.com/lestrrat-go/blackmagic v1.0.3 h1:94HXkVLxkZO9vJI/w2u1T0DAoprShFd13xtnSINtDWs= -github.com/lestrrat-go/blackmagic v1.0.3/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= +github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA= +github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= github.com/lestrrat-go/httprc v1.0.6 h1:qgmgIRhpvBqexMJjA/PmwSvhNk679oqD1RbovdCGW8k= @@ -640,22 +650,18 @@ github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNB github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= -github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= -github.com/libp2p/go-libp2p v0.25.1 h1:YK+YDCHpYyTvitKWVxa5PfElgIpOONU01X5UcLEwJGA= -github.com/libp2p/go-libp2p v0.25.1/go.mod h1:xnK9/1d9+jeQCVvi/f1g12KqtVi/jP/SijtKV1hML3g= -github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= -github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= -github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= -github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= +github.com/libp2p/go-libp2p v0.41.1 h1:8ecNQVT5ev/jqALTvisSJeVNvXYJyK4NhQx1nNRXQZE= +github.com/libp2p/go-libp2p v0.41.1/go.mod h1:DcGTovJzQl/I7HMrby5ZRjeD0kQkGiy+9w6aEkSZpRI= +github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= +github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= +github.com/libp2p/go-libp2p-record v0.3.1 h1:cly48Xi5GjNw5Wq+7gmjfBiG9HCzQVkiZOUZ8kUl+Fg= +github.com/libp2p/go-libp2p-record v0.3.1/go.mod h1:T8itUkLcWQLCYMqtX7Th6r7SexyUJpIyPgks757td/E= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= -github.com/libp2p/go-nat v0.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= -github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= -github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= -github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= +github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8= +github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE= github.com/livepeer/joy4 v0.1.2-0.20191121080656-b2fea45cbded/go.mod h1:xkDdm+akniYxVT9KW1Y2Y7Hso6aW+rZObz3nrA9yTHw= github.com/livepeer/m3u8 v0.11.1 h1:VkUJzfNTyjy9mqsgp5JPvouwna8wGZMvd/gAfT5FinU= github.com/livepeer/m3u8 v0.11.1/go.mod h1:IUqAtwWPAG2CblfQa4SVzTQoDcEMPyfNOaBSxqHMS04= @@ -679,7 +685,6 @@ github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= -github.com/mattn/go-isatty v0.0.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/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= @@ -693,8 +698,6 @@ github.com/mgechev/revive v1.9.0 h1:8LaA62XIKrb8lM6VsBSQ92slt/o92z5+hTw3CmrvSrM= github.com/mgechev/revive v1.9.0/go.mod h1:LAPq3+MgOf7GcL5PlWIkHb0PT7XH4NuC2LdWymhb9Mo= github.com/microsoft/go-mssqldb v0.17.0 h1:Fto83dMZPnYv1Zwx5vHHxpNraeEaUlQ/hhHLgZiaenE= github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= -github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= @@ -720,20 +723,18 @@ github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aG github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= -github.com/multiformats/go-multiaddr v0.8.0 h1:aqjksEcqK+iD/Foe1RRFsGZh8+XFiGo7FgUCZlpv3LU= -github.com/multiformats/go-multiaddr v0.8.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs= -github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= -github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= +github.com/multiformats/go-multiaddr v0.16.0 h1:oGWEVKioVQcdIOBlYM8BH1rZDWOGJSqr9/BKl6zQ4qc= +github.com/multiformats/go-multiaddr v0.16.0/go.mod h1:JSVUmXDjsVFiW7RjIFMP7+Ev+h1DTbiJgVeTV/tcmP0= github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= -github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= -github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= +github.com/multiformats/go-multicodec v0.9.1 h1:x/Fuxr7ZuR4jJV4Os5g444F7xC4XmyUaT/FWtE+9Zjo= +github.com/multiformats/go-multicodec v0.9.1/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy+h3EbkMTek1m+Fybbo= github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.4.1 h1:rFy0Iiyn3YT0asivDUIR05leAdwZq3de4741sbiSdfo= -github.com/multiformats/go-multistream v0.4.1/go.mod h1:Mz5eykRVAjJWckE2U78c6xqdtyNUEhKSM0Lwar2p77Q= +github.com/multiformats/go-multistream v0.6.1 h1:4aoX5v6T+yWmc2raBHsTvzmFhOI8WVOer28DeBBEYdQ= +github.com/multiformats/go-multistream v0.6.1/go.mod h1:ksQf6kqHAb6zIsyw7Zm+gAuVo57Qbq84E27YlYqavqw= 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= @@ -772,38 +773,44 @@ github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 h1:1/WtZae0yGtPq+TI6+ github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9/go.mod h1:x3N5drFsm2uilKKuuYo6LdyD8vZAW55sH/9w+pbo1sw= github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= -github.com/pion/datachannel v1.5.9 h1:LpIWAOYPyDrXtU+BW7X0Yt/vGtYxtXQ8ql7dFfYUVZA= -github.com/pion/datachannel v1.5.9/go.mod h1:kDUuk4CU4Uxp82NH4LQZbISULkX/HtzKa4P7ldf9izE= +github.com/pion/datachannel v1.5.10 h1:ly0Q26K1i6ZkGf42W7D4hQYR90pZwzFOjTq5AuCKk4o= +github.com/pion/datachannel v1.5.10/go.mod h1:p/jJfC9arb29W7WrxyKbepTU20CFgyx5oLo8Rs4Py/M= +github.com/pion/dtls/v2 v2.2.12 h1:KP7H5/c1EiVAAKUmXyCzPiQe5+bCJrpOeKg/L05dunk= +github.com/pion/dtls/v2 v2.2.12/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= github.com/pion/dtls/v3 v3.0.4 h1:44CZekewMzfrn9pmGrj5BNnTMDCFwr+6sLH+cCuLM7U= github.com/pion/dtls/v3 v3.0.4/go.mod h1:R373CsjxWqNPf6MEkfdy3aSe9niZvL/JaKlGeFphtMg= -github.com/pion/ice/v4 v4.0.3 h1:9s5rI1WKzF5DRqhJ+Id8bls/8PzM7mau0mj1WZb4IXE= -github.com/pion/ice/v4 v4.0.3/go.mod h1:VfHy0beAZ5loDT7BmJ2LtMtC4dbawIkkkejHPRZNB3Y= +github.com/pion/ice/v4 v4.0.8 h1:ajNx0idNG+S+v9Phu4LSn2cs8JEfTsA1/tEjkkAVpFY= +github.com/pion/ice/v4 v4.0.8/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw= github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI= github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y= -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/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI= +github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90= github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM= github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA= github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= -github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= -github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtp v1.8.9 h1:E2HX740TZKaqdcPmf4pw6ZZuG8u5RlMMt+l3dxeu6Wk= -github.com/pion/rtp v1.8.9/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/sctp v1.8.34 h1:rCuD3m53i0oGxCSp7FLQKvqVx0Nf5AUAHhMRXTTQjBc= -github.com/pion/sctp v1.8.34/go.mod h1:yWkCClkXlzVW7BXfI2PjrUGBwUI0CjXJBkhLt+sdo4U= -github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= -github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= +github.com/pion/rtcp v1.2.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo= +github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0= +github.com/pion/rtp v1.8.11 h1:17xjnY5WO5hgO6SD3/NTIUPvSFw/PbLsIJyz1r1yNIk= +github.com/pion/rtp v1.8.11/go.mod h1:8uMBJj32Pa1wwx8Fuv/AsFhn8jsgw+3rUC2PfoBZ8p4= +github.com/pion/sctp v1.8.37 h1:ZDmGPtRPX9mKCiVXtMbTWybFw3z/hVKAZgU81wcOrqs= +github.com/pion/sctp v1.8.37/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE= +github.com/pion/sdp/v3 v3.0.10 h1:6MChLE/1xYB+CjumMw+gZ9ufp2DPApuVSnDT8t5MIgA= +github.com/pion/sdp/v3 v3.0.10/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E= github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M= github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ= +github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= +github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw= github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU= +github.com/pion/transport/v2 v2.2.10 h1:ucLBLE8nuxiHfvkFKnkDQRYWYfp8ejf4YBOPfaQpw6Q= +github.com/pion/transport/v2 v2.2.10/go.mod h1:sq1kSLWs+cHW9E+2fJP95QudkzbK7wscs8yYgQToO5E= github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0= github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo= github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM= github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA= -github.com/pion/webrtc/v4 v4.0.5 h1:8cVPojcv3cQTwVga2vF1rzCNvkiEimnYdCCG7yF317I= -github.com/pion/webrtc/v4 v4.0.5/go.mod h1:LvP8Np5b/sM0uyJIcUPvJcCvhtjHxJwzh2H2PYzE6cQ= +github.com/pion/webrtc/v4 v4.0.10 h1:Hq/JLjhqLxi+NmCtE8lnRPDr8H4LcNvwg8OxVcdv56Q= +github.com/pion/webrtc/v4 v4.0.10/go.mod h1:ViHLVaNpiuvaH8pdiuQxuA9awuE6KVzAXx3vVWilOck= github.com/piprate/json-gold v0.5.0 h1:RmGh1PYboCFcchVFuh2pbSWAZy4XJaqTMU4KQYsApbM= github.com/piprate/json-gold v0.5.0/go.mod h1:WZ501QQMbZZ+3pXFPhQKzNwS1+jls0oqov3uQ2WasLs= github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= @@ -822,15 +829,15 @@ github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 h1:J9b7z+QKAm github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= -github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4= -github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.59.1 h1:LXb1quJHWm1P6wq/U824uxYi4Sg0oGvNeUm1z5dJoX0= -github.com/prometheus/common v0.59.1/go.mod h1:GpWM7dewqmVYcd7SmRaiWVe9SSqjf0UrwnYnpEZNuT0= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= +github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/quasilyte/go-ruleguard v0.4.4 h1:53DncefIeLX3qEpjzlS1lyUmQoUEeOWPFWqaTJq9eAQ= github.com/quasilyte/go-ruleguard v0.4.4/go.mod h1:Vl05zJ538vcEEwu16V/Hdu7IYZWyKSwIy4c88Ro1kRE= github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe60+5DqOpCjPE= @@ -841,6 +848,12 @@ github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= +github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI= +github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg= +github.com/quic-go/quic-go v0.50.1 h1:unsgjFIUqW8a2oopkY7YNONpV1gYND6Nt9hnt1PN94Q= +github.com/quic-go/quic-go v0.50.1/go.mod h1:Vim6OmUvlYdwBhXP9ZVrtGmCMWa3wEqhq3NgYrI8b4E= +github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66 h1:4WFk6u3sOT6pLa1kQ50ZVdm8BQFgJNA117cepZxtLIg= +github.com/quic-go/webtransport-go v0.8.1-0.20241018022711-4ac2c9250e66/go.mod h1:Vp72IJajgeOL6ddqrAhmp7IM9zbTcgkQxD/YdxrVwMw= github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI= github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -921,12 +934,12 @@ github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YE github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/stbenjam/no-sprintf-host-port v0.2.0 h1:i8pxvGrt1+4G0czLr/WnmyH7zbZ8Bg8etvARQ1rpyl4= github.com/stbenjam/no-sprintf-host-port v0.2.0/go.mod h1:eL0bQ9PasS0hsyTyfTjjG+E80QIyPnBVQbYZyv20Jfk= -github.com/streamplace/atproto-oauth-golang v0.0.0-20250521042753-9cfa9e504155 h1:OAJ2Hh9XQcU77aUdxgT5tTcGKLYzwCXvPWR22V5xV5o= -github.com/streamplace/atproto-oauth-golang v0.0.0-20250521042753-9cfa9e504155/go.mod h1:/AUT+i6CBJJ13AWx89XyvFdSkmDT3IoEg8pl34MaUgs= +github.com/streamplace/atproto-oauth-golang v0.0.0-20250619231223-a9c04fb888ac h1:heVM4CGox3kfJclSmagsI3hvKk7W52EegnFqqs9CSYk= +github.com/streamplace/atproto-oauth-golang v0.0.0-20250619231223-a9c04fb888ac/go.mod h1:9LlKkqciiO5lRfbX0n4Wn5KNY9nvFb4R3by8FdW2TWc= github.com/streamplace/go-dpop v0.0.0-20250510031900-c897158a8ad4 h1:L1fS4HJSaAyNnkwfuZubgfeZy8rkWmA0cMtH5Z0HqNc= github.com/streamplace/go-dpop v0.0.0-20250510031900-c897158a8ad4/go.mod h1:bGUXY9Wd4mnd+XUrOYZr358J2f6z9QO/dLhL1SsiD+0= -github.com/streamplace/oatproxy v0.0.0-20250531005031-5c1979905fdc h1:n/+UpyqzUI3AVbyGSlwearyMt2ClN3esoUwmCd7vvKk= -github.com/streamplace/oatproxy v0.0.0-20250531005031-5c1979905fdc/go.mod h1:YlNOtaWvIoAZ5rxKENNFIsa5aWtAWdMY3Slm3lzWGbU= +github.com/streamplace/oatproxy v0.0.0-20250619231549-b15df1b82a3a h1:rbfSEm9IgK6jhXXtOExexL+ACNDOE/zJ5VYp6ujTpCA= +github.com/streamplace/oatproxy v0.0.0-20250619231549-b15df1b82a3a/go.mod h1:pXi24hA7xBHj8eEywX6wGqJOR9FaEYlGwQ/72rN6okw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -942,7 +955,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= @@ -996,8 +1008,10 @@ github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSD github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 h1:5HZfQkwe0mIfyDmc1Em5GqlNRzcdtlv4HTNmdpt7XH0= github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11/go.mod h1:Wlo/SzPmxVp6vXpGt/zaXhHH0fn4IxgqZc82aKg6bpQ= -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.3.1 h1:82ioxmhEYut7LBVGhGq8xoRkXPLElVuh5mV67AFfdv0= +github.com/whyrusleeping/cbor-gen v0.3.1/go.mod h1:pM99HXyEbSQHcosHc0iW7YFmwnscr+t9Te4ibko05so= +github.com/whyrusleeping/go-did v0.0.0-20230824162731-404d1707d5d6 h1:yJ9/LwIGIk/c0CdoavpC9RNSGSruIspSZtxG3Nnldic= +github.com/whyrusleeping/go-did v0.0.0-20230824162731-404d1707d5d6/go.mod h1:39U9RRVr4CKbXpXYopWn+FSH5s+vWu6+RmguSPWAq5s= github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= github.com/wlynxg/anet v0.0.5/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= @@ -1045,22 +1059,22 @@ go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJyS go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= +go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= +go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1069,18 +1083,18 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= +go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= +go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1091,11 +1105,11 @@ golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2Uz golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= -golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4= +golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac h1:TSSpLIG4v+p0rPv1pNOQtl1I8knsO4S9trOxNMOLVP4= @@ -1118,8 +1132,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1143,8 +1157,8 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= +golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= @@ -1159,8 +1173,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/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= @@ -1173,7 +1187,6 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 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-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1187,8 +1200,8 @@ 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.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -1197,8 +1210,8 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= -golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -1209,8 +1222,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= +golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1241,14 +1254,14 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= -golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= -golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY= +golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.228.0 h1:X2DJ/uoWGnY5obVjewbp8icSL5U4FzuCfy9OjbLSnLs= google.golang.org/api v0.228.0/go.mod h1:wNvRS1Pbe8r4+IfBIniV8fwCpGwTrYa+kMUDiC5z5a4= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= @@ -1297,11 +1310,9 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= 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.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gorm.io/datatypes v1.2.4 h1:uZmGAcK/QZ0uyfCuVg0VQY1ZmV9h1fuG0tMwKByO1z4= @@ -1322,8 +1333,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.6.1 h1:R094WgE8K4JirYjBaOpz/AvTyUu/3wbmAoskKN/pxTI= honnef.co/go/tools v0.6.1/go.mod h1:3puzxxljPCe8RGJX7BIy1plGbxEOZni5mR2aXe3/uk4= -lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= -lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.4.1 h1:I3Smz7gso8w4/TunLKec6K2fn+kyKtDxr/xcQEN84Wg= +lukechampine.com/blake3 v1.4.1/go.mod h1:QFosUxmjB8mnrWFSNwKmvxHpfY72bmD2tQ0kBMM3kwo= mvdan.cc/gofumpt v0.8.0 h1:nZUCeC2ViFaerTcYKstMmfysj6uhQrA2vJe+2vwGU6k= mvdan.cc/gofumpt v0.8.0/go.mod h1:vEYnSzyGPmjvFkqJWtXkh79UwPWP9/HMxQdGEXZHjpg= mvdan.cc/unparam v0.0.0-20250301125049-0df0534333a4 h1:WjUu4yQoT5BHT1w8Zu56SP8367OuBV5jvo+4Ulppyf8= diff --git a/js/docs/src/content/docs/lex-reference/openapi.json b/js/docs/src/content/docs/lex-reference/openapi.json index 524fa8c74..caad90af3 100644 --- a/js/docs/src/content/docs/lex-reference/openapi.json +++ b/js/docs/src/content/docs/lex-reference/openapi.json @@ -163,6 +163,514 @@ ] } }, + "/xrpc/com.atproto.sync.getRecord": { + "get": { + "summary": "Get data blocks needed to prove the existence or non-existence of record in the current version of repo. Does not require auth.", + "operationId": "com.atproto.sync.getRecord", + "tags": ["com.atproto.sync"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/vnd.ipld.car": { + "schema": {} + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "RecordNotFound" + }, + { + "const": "RepoNotFound" + }, + { + "const": "RepoTakendown" + }, + { + "const": "RepoSuspended" + }, + { + "const": "RepoDeactivated" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "did", + "in": "query", + "required": true, + "description": "The DID of the repo.", + "schema": { + "type": "string", + "description": "The DID of the repo.", + "format": "did" + } + }, + { + "name": "collection", + "in": "query", + "required": true, + "schema": { + "type": "string", + "format": "nsid" + } + }, + { + "name": "rkey", + "in": "query", + "required": true, + "description": "Record Key", + "schema": { + "type": "string", + "description": "Record Key", + "format": "record-key" + } + } + ] + } + }, + "/xrpc/com.atproto.sync.listRepos": { + "get": { + "summary": "Enumerates all the DID, rev, and commit CID for all repos hosted by this service. Does not require auth; implemented by PDS and Relay.", + "operationId": "com.atproto.sync.listRepos", + "tags": ["com.atproto.sync"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "cursor": { + "type": "string" + }, + "repos": { + "type": "array", + "items": { + "$ref": "#/components/schemas/com.atproto.sync.listRepos_repo" + } + } + }, + "required": ["repos"] + } + } + } + } + }, + "parameters": [ + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "default": 500, + "minimum": 1, + "maximum": 1000 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + } + ] + } + }, + "/xrpc/com.atproto.sync.subscribeRepos": { + "get": { + "summary": "Repository event stream, aka Firehose endpoint. Outputs repo commits with diff data, and identity update events, for all repositories on the current server. See the atproto specifications for details around stream sequencing, repo versioning, CAR diff format, and more. Public and does not require auth; implemented by PDS and Relay.", + "operationId": "com.atproto.sync.subscribeRepos", + "tags": ["com.atproto.sync"], + "x-websocket": true, + "responses": { + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "FutureCursor" + }, + { + "const": "ConsumerTooSlow" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "cursor", + "in": "query", + "required": false, + "description": "The last known event seq number to backfill from.", + "schema": { + "type": "integer", + "description": "The last known event seq number to backfill from." + } + } + ], + "x-websocket-message": { + "schema": { + "oneOf": [ + { + "$ref": "#/components/schemas/com.atproto.sync.subscribeRepos_commit" + }, + { + "$ref": "#/components/schemas/com.atproto.sync.subscribeRepos_sync" + }, + { + "$ref": "#/components/schemas/com.atproto.sync.subscribeRepos_identity" + }, + { + "$ref": "#/components/schemas/com.atproto.sync.subscribeRepos_account" + }, + { + "$ref": "#/components/schemas/com.atproto.sync.subscribeRepos_info" + } + ] + } + } + } + }, + "/xrpc/com.atproto.server.describeServer": { + "get": { + "summary": "Describes the server's account creation requirements and capabilities. Implemented by PDS.", + "operationId": "com.atproto.server.describeServer", + "tags": ["com.atproto.server"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "inviteCodeRequired": { + "type": "boolean", + "description": "If true, an invite code must be supplied to create an account on this instance." + }, + "phoneVerificationRequired": { + "type": "boolean", + "description": "If true, a phone verification token must be supplied to create an account on this instance." + }, + "availableUserDomains": { + "type": "array", + "description": "List of domain suffixes that can be used in account handles.", + "items": { + "type": "string" + } + }, + "links": { + "$ref": "#/components/schemas/com.atproto.server.describeServer_links", + "description": "URLs of service policy documents." + }, + "contact": { + "$ref": "#/components/schemas/com.atproto.server.describeServer_contact", + "description": "Contact information" + }, + "did": { + "type": "string", + "format": "did" + } + }, + "required": ["did", "availableUserDomains"] + } + } + } + } + } + } + }, + "/xrpc/com.atproto.repo.describeRepo": { + "get": { + "summary": "Get information about an account and repository, including the list of collections. Does not require auth.", + "operationId": "com.atproto.repo.describeRepo", + "tags": ["com.atproto.repo"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "handle": { + "type": "string", + "format": "handle" + }, + "did": { + "type": "string", + "format": "did" + }, + "didDoc": { + "description": "The complete DID document for this account." + }, + "collections": { + "type": "array", + "description": "List of all the collections (NSIDs) for which this repo contains at least one record.", + "items": { + "type": "string", + "format": "nsid" + } + }, + "handleIsCorrect": { + "type": "boolean", + "description": "Indicates if handle is currently valid (resolves bi-directionally)" + } + }, + "required": [ + "handle", + "did", + "didDoc", + "collections", + "handleIsCorrect" + ] + } + } + } + } + }, + "parameters": [ + { + "name": "repo", + "in": "query", + "required": true, + "description": "The handle or DID of the repo.", + "schema": { + "type": "string", + "description": "The handle or DID of the repo.", + "format": "at-identifier" + } + } + ] + } + }, + "/xrpc/com.atproto.repo.getRecord": { + "get": { + "summary": "Get a single record from a repository. Does not require auth.", + "operationId": "com.atproto.repo.getRecord", + "tags": ["com.atproto.repo"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri" + }, + "cid": { + "type": "string", + "format": "cid" + }, + "value": {} + }, + "required": ["uri", "value"] + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": ["error", "message"], + "properties": { + "error": { + "type": "string", + "oneOf": [ + { + "const": "RecordNotFound" + } + ] + }, + "message": { + "type": "string" + } + } + } + } + } + } + }, + "parameters": [ + { + "name": "repo", + "in": "query", + "required": true, + "description": "The handle or DID of the repo.", + "schema": { + "type": "string", + "description": "The handle or DID of the repo.", + "format": "at-identifier" + } + }, + { + "name": "collection", + "in": "query", + "required": true, + "description": "The NSID of the record collection.", + "schema": { + "type": "string", + "description": "The NSID of the record collection.", + "format": "nsid" + } + }, + { + "name": "rkey", + "in": "query", + "required": true, + "description": "The Record Key.", + "schema": { + "type": "string", + "description": "The Record Key.", + "format": "record-key" + } + }, + { + "name": "cid", + "in": "query", + "required": false, + "description": "The CID of the version of the record. If not specified, then return the most recent version.", + "schema": { + "type": "string", + "description": "The CID of the version of the record. If not specified, then return the most recent version.", + "format": "cid" + } + } + ] + } + }, + "/xrpc/com.atproto.repo.listRecords": { + "get": { + "summary": "List a range of records in a repository, matching a specific collection. Does not require auth.", + "operationId": "com.atproto.repo.listRecords", + "tags": ["com.atproto.repo"], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "cursor": { + "type": "string" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/com.atproto.repo.listRecords_record" + } + } + }, + "required": ["records"] + } + } + } + } + }, + "parameters": [ + { + "name": "repo", + "in": "query", + "required": true, + "description": "The handle or DID of the repo.", + "schema": { + "type": "string", + "description": "The handle or DID of the repo.", + "format": "at-identifier" + } + }, + { + "name": "collection", + "in": "query", + "required": true, + "description": "The NSID of the record type.", + "schema": { + "type": "string", + "description": "The NSID of the record type.", + "format": "nsid" + } + }, + { + "name": "limit", + "in": "query", + "required": false, + "description": "The number of records to return.", + "schema": { + "type": "integer", + "description": "The number of records to return.", + "default": 50, + "minimum": 1, + "maximum": 100 + } + }, + { + "name": "cursor", + "in": "query", + "required": false, + "schema": { + "type": "string" + } + }, + { + "name": "reverse", + "in": "query", + "required": false, + "description": "Flag to reverse the order of the returned records.", + "schema": { + "type": "boolean", + "description": "Flag to reverse the order of the returned records." + } + } + ] + } + }, "/xrpc/com.atproto.repo.uploadBlob": { "post": { "summary": "Upload a new blob, to be referenced from a repository record. The blob will be deleted if it is not referenced within a time window (eg, minutes). Blob restrictions (mimetype, size, etc) are enforced when the reference is created. Requires auth, implemented by PDS.", @@ -779,6 +1287,269 @@ }, "required": ["uri", "cid"] }, + "com.atproto.sync.listRepos_repo": { + "type": "object", + "properties": { + "did": { + "type": "string", + "format": "did" + }, + "head": { + "type": "string", + "description": "Current repo commit CID", + "format": "cid" + }, + "rev": { + "type": "string", + "format": "tid" + }, + "active": { + "type": "boolean" + }, + "status": { + "type": "string", + "description": "If active=false, this optional field indicates a possible reason for why the account is not active. If active=false and no status is supplied, then the host makes no claim for why the repository is no longer being hosted." + } + }, + "required": ["did", "head", "rev"] + }, + "com.atproto.sync.subscribeRepos_commit": { + "type": "object", + "description": "Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature.", + "properties": { + "seq": { + "type": "integer", + "description": "The stream sequence number of this message." + }, + "rebase": { + "type": "boolean", + "description": "DEPRECATED -- unused" + }, + "tooBig": { + "type": "boolean", + "description": "DEPRECATED -- replaced by #sync event and data limits. Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data." + }, + "repo": { + "type": "string", + "description": "The repo this event comes from. Note that all other message types name this field 'did'.", + "format": "did" + }, + "commit": { + "type": "string", + "description": "Repo commit object CID." + }, + "rev": { + "type": "string", + "description": "The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event.", + "format": "tid" + }, + "since": { + "oneOf": [ + { + "type": "string", + "description": "The rev of the last emitted commit from this repo (if any).", + "format": "tid" + } + ] + }, + "blocks": { + "type": "string", + "format": "byte", + "description": "CAR file containing relevant blocks, as a diff since the previous repo state. The commit must be included as a block, and the commit block CID must be the first entry in the CAR header 'roots' list.", + "maxLength": 2000000 + }, + "ops": { + "type": "array", + "items": { + "$ref": "#/components/schemas/com.atproto.sync.subscribeRepos_repoOp", + "description": "List of repo mutation operations in this commit (eg, records created, updated, or deleted)." + }, + "maxItems": 200 + }, + "blobs": { + "type": "array", + "items": { + "type": "string", + "description": "DEPRECATED -- will soon always be empty. List of new blobs (by CID) referenced by records in this commit." + } + }, + "prevData": { + "type": "string", + "description": "The root CID of the MST tree for the previous commit from this repo (indicated by the 'since' revision field in this message). Corresponds to the 'data' field in the repo commit object. NOTE: this field is effectively required for the 'inductive' version of firehose." + }, + "time": { + "type": "string", + "description": "Timestamp of when this message was originally broadcast.", + "format": "date-time" + } + }, + "required": [ + "seq", + "rebase", + "tooBig", + "repo", + "commit", + "rev", + "since", + "blocks", + "ops", + "blobs", + "time" + ] + }, + "com.atproto.sync.subscribeRepos_repoOp": { + "type": "object", + "description": "A repo operation, ie a mutation of a single record.", + "properties": { + "action": { + "type": "string" + }, + "path": { + "type": "string" + }, + "cid": { + "oneOf": [ + { + "type": "string", + "description": "For creates and updates, the new record CID. For deletions, null." + } + ] + }, + "prev": { + "type": "string", + "description": "For updates and deletes, the previous record CID (required for inductive firehose). For creations, field should not be defined." + } + }, + "required": ["action", "path", "cid"] + }, + "com.atproto.sync.subscribeRepos_sync": { + "type": "object", + "description": "Updates the repo to a new state, without necessarily including that state on the firehose. Used to recover from broken commit streams, data loss incidents, or in situations where upstream host does not know recent state of the repository.", + "properties": { + "seq": { + "type": "integer", + "description": "The stream sequence number of this message." + }, + "did": { + "type": "string", + "description": "The account this repo event corresponds to. Must match that in the commit object.", + "format": "did" + }, + "blocks": { + "type": "string", + "format": "byte", + "description": "CAR file containing the commit, as a block. The CAR header must include the commit block CID as the first 'root'.", + "maxLength": 10000 + }, + "rev": { + "type": "string", + "description": "The rev of the commit. This value must match that in the commit object." + }, + "time": { + "type": "string", + "description": "Timestamp of when this message was originally broadcast.", + "format": "date-time" + } + }, + "required": ["seq", "did", "blocks", "rev", "time"] + }, + "com.atproto.sync.subscribeRepos_identity": { + "type": "object", + "description": "Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache.", + "properties": { + "seq": { + "type": "integer" + }, + "did": { + "type": "string", + "format": "did" + }, + "time": { + "type": "string", + "format": "date-time" + }, + "handle": { + "type": "string", + "description": "The current handle for the account, or 'handle.invalid' if validation fails. This field is optional, might have been validated or passed-through from an upstream source. Semantics and behaviors for PDS vs Relay may evolve in the future; see atproto specs for more details.", + "format": "handle" + } + }, + "required": ["seq", "did", "time"] + }, + "com.atproto.sync.subscribeRepos_account": { + "type": "object", + "description": "Represents a change to an account's status on a host (eg, PDS or Relay). The semantics of this event are that the status is at the host which emitted the event, not necessarily that at the currently active PDS. Eg, a Relay takedown would emit a takedown with active=false, even if the PDS is still active.", + "properties": { + "seq": { + "type": "integer" + }, + "did": { + "type": "string", + "format": "did" + }, + "time": { + "type": "string", + "format": "date-time" + }, + "active": { + "type": "boolean", + "description": "Indicates that the account has a repository which can be fetched from the host that emitted this event." + }, + "status": { + "type": "string", + "description": "If active=false, this optional field indicates a reason for why the account is not active." + } + }, + "required": ["seq", "did", "time", "active"] + }, + "com.atproto.sync.subscribeRepos_info": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "message": { + "type": "string" + } + }, + "required": ["name"] + }, + "com.atproto.server.describeServer_links": { + "type": "object", + "properties": { + "privacyPolicy": { + "type": "string", + "format": "uri" + }, + "termsOfService": { + "type": "string", + "format": "uri" + } + } + }, + "com.atproto.server.describeServer_contact": { + "type": "object", + "properties": { + "email": { + "type": "string" + } + } + }, + "com.atproto.repo.listRecords_record": { + "type": "object", + "properties": { + "uri": { + "type": "string", + "format": "uri" + }, + "cid": { + "type": "string", + "format": "cid" + }, + "value": {} + }, + "required": ["uri", "cid", "value"] + }, "app.bsky.feed.defs_skeletonFeedPost": { "type": "object", "properties": { diff --git a/js/docs/src/content/docs/lex-reference/place-stream-livestream.md b/js/docs/src/content/docs/lex-reference/place-stream-livestream.md index b8434f0fb..339198311 100644 --- a/js/docs/src/content/docs/lex-reference/place-stream-livestream.md +++ b/js/docs/src/content/docs/lex-reference/place-stream-livestream.md @@ -21,7 +21,7 @@ Record announcing a livestream is happening | Name | Type | Req'd | Description | Constraints | | ----------- | -------------------------------------------------------------------------------------------------------------------------------------- | ----- | -------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------- | -| `title` | `string` | ✅ | The title of the livestream, as it will be announced to followers. | Max Length: 1400
Max Graphemes: 140 | +| `title` | `string` | ✅ | The title of the livestream, as it will be announced to followers! | Max Length: 1400
Max Graphemes: 140 | | `url` | `string` | ❌ | The URL where this stream can be found. This is primarily a hint for other Streamplace nodes to locate and replicate the stream. | Format: `uri` | | `createdAt` | `string` | ✅ | Client-declared timestamp when this livestream started. | Format: `datetime` | | `post` | [`com.atproto.repo.strongRef`](https://github.com/bluesky-social/atproto/tree/main/lexicons/com/atproto/repo/strongref.json#undefined) | ❌ | The post that announced this livestream. | | @@ -95,7 +95,7 @@ Record announcing a livestream is happening "type": "string", "maxLength": 1400, "maxGraphemes": 140, - "description": "The title of the livestream, as it will be announced to followers." + "description": "The title of the livestream, as it will be announced to followers!" }, "url": { "type": "string", diff --git a/lexicons/com/atproto/repo/describeRepo.json b/lexicons/com/atproto/repo/describeRepo.json new file mode 100644 index 000000000..b1ce2b6cf --- /dev/null +++ b/lexicons/com/atproto/repo/describeRepo.json @@ -0,0 +1,51 @@ +{ + "lexicon": 1, + "id": "com.atproto.repo.describeRepo", + "defs": { + "main": { + "type": "query", + "description": "Get information about an account and repository, including the list of collections. Does not require auth.", + "parameters": { + "type": "params", + "required": ["repo"], + "properties": { + "repo": { + "type": "string", + "format": "at-identifier", + "description": "The handle or DID of the repo." + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": [ + "handle", + "did", + "didDoc", + "collections", + "handleIsCorrect" + ], + "properties": { + "handle": { "type": "string", "format": "handle" }, + "did": { "type": "string", "format": "did" }, + "didDoc": { + "type": "unknown", + "description": "The complete DID document for this account." + }, + "collections": { + "type": "array", + "description": "List of all the collections (NSIDs) for which this repo contains at least one record.", + "items": { "type": "string", "format": "nsid" } + }, + "handleIsCorrect": { + "type": "boolean", + "description": "Indicates if handle is currently valid (resolves bi-directionally)" + } + } + } + } + } + } +} diff --git a/lexicons/com/atproto/repo/getRecord.json b/lexicons/com/atproto/repo/getRecord.json new file mode 100644 index 000000000..388b9c5ad --- /dev/null +++ b/lexicons/com/atproto/repo/getRecord.json @@ -0,0 +1,49 @@ +{ + "lexicon": 1, + "id": "com.atproto.repo.getRecord", + "defs": { + "main": { + "type": "query", + "description": "Get a single record from a repository. Does not require auth.", + "parameters": { + "type": "params", + "required": ["repo", "collection", "rkey"], + "properties": { + "repo": { + "type": "string", + "format": "at-identifier", + "description": "The handle or DID of the repo." + }, + "collection": { + "type": "string", + "format": "nsid", + "description": "The NSID of the record collection." + }, + "rkey": { + "type": "string", + "description": "The Record Key.", + "format": "record-key" + }, + "cid": { + "type": "string", + "format": "cid", + "description": "The CID of the version of the record. If not specified, then return the most recent version." + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["uri", "value"], + "properties": { + "uri": { "type": "string", "format": "at-uri" }, + "cid": { "type": "string", "format": "cid" }, + "value": { "type": "unknown" } + } + } + }, + "errors": [{ "name": "RecordNotFound" }] + } + } +} diff --git a/lexicons/com/atproto/repo/listRecords.json b/lexicons/com/atproto/repo/listRecords.json new file mode 100644 index 000000000..3d43ff40b --- /dev/null +++ b/lexicons/com/atproto/repo/listRecords.json @@ -0,0 +1,61 @@ +{ + "lexicon": 1, + "id": "com.atproto.repo.listRecords", + "defs": { + "main": { + "type": "query", + "description": "List a range of records in a repository, matching a specific collection. Does not require auth.", + "parameters": { + "type": "params", + "required": ["repo", "collection"], + "properties": { + "repo": { + "type": "string", + "format": "at-identifier", + "description": "The handle or DID of the repo." + }, + "collection": { + "type": "string", + "format": "nsid", + "description": "The NSID of the record type." + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 50, + "description": "The number of records to return." + }, + "cursor": { "type": "string" }, + "reverse": { + "type": "boolean", + "description": "Flag to reverse the order of the returned records." + } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["records"], + "properties": { + "cursor": { "type": "string" }, + "records": { + "type": "array", + "items": { "type": "ref", "ref": "#record" } + } + } + } + } + }, + "record": { + "type": "object", + "required": ["uri", "cid", "value"], + "properties": { + "uri": { "type": "string", "format": "at-uri" }, + "cid": { "type": "string", "format": "cid" }, + "value": { "type": "unknown" } + } + } + } +} diff --git a/lexicons/com/atproto/server/describeServer.json b/lexicons/com/atproto/server/describeServer.json new file mode 100644 index 000000000..bbecf651e --- /dev/null +++ b/lexicons/com/atproto/server/describeServer.json @@ -0,0 +1,59 @@ +{ + "lexicon": 1, + "id": "com.atproto.server.describeServer", + "defs": { + "main": { + "type": "query", + "description": "Describes the server's account creation requirements and capabilities. Implemented by PDS.", + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["did", "availableUserDomains"], + "properties": { + "inviteCodeRequired": { + "type": "boolean", + "description": "If true, an invite code must be supplied to create an account on this instance." + }, + "phoneVerificationRequired": { + "type": "boolean", + "description": "If true, a phone verification token must be supplied to create an account on this instance." + }, + "availableUserDomains": { + "type": "array", + "description": "List of domain suffixes that can be used in account handles.", + "items": { "type": "string" } + }, + "links": { + "type": "ref", + "description": "URLs of service policy documents.", + "ref": "#links" + }, + "contact": { + "type": "ref", + "description": "Contact information", + "ref": "#contact" + }, + "did": { + "type": "string", + "format": "did" + } + } + } + } + }, + "links": { + "type": "object", + "properties": { + "privacyPolicy": { "type": "string", "format": "uri" }, + "termsOfService": { "type": "string", "format": "uri" } + } + }, + "contact": { + "type": "object", + "properties": { + "email": { "type": "string" } + } + } + } +} diff --git a/lexicons/com/atproto/sync/getRecord.json b/lexicons/com/atproto/sync/getRecord.json new file mode 100644 index 000000000..ecfc5acc4 --- /dev/null +++ b/lexicons/com/atproto/sync/getRecord.json @@ -0,0 +1,37 @@ +{ + "lexicon": 1, + "id": "com.atproto.sync.getRecord", + "defs": { + "main": { + "type": "query", + "description": "Get data blocks needed to prove the existence or non-existence of record in the current version of repo. Does not require auth.", + "parameters": { + "type": "params", + "required": ["did", "collection", "rkey"], + "properties": { + "did": { + "type": "string", + "format": "did", + "description": "The DID of the repo." + }, + "collection": { "type": "string", "format": "nsid" }, + "rkey": { + "type": "string", + "description": "Record Key", + "format": "record-key" + } + } + }, + "output": { + "encoding": "application/vnd.ipld.car" + }, + "errors": [ + { "name": "RecordNotFound" }, + { "name": "RepoNotFound" }, + { "name": "RepoTakendown" }, + { "name": "RepoSuspended" }, + { "name": "RepoDeactivated" } + ] + } + } +} diff --git a/lexicons/com/atproto/sync/listRepos.json b/lexicons/com/atproto/sync/listRepos.json new file mode 100644 index 000000000..8115bbd68 --- /dev/null +++ b/lexicons/com/atproto/sync/listRepos.json @@ -0,0 +1,62 @@ +{ + "lexicon": 1, + "id": "com.atproto.sync.listRepos", + "defs": { + "main": { + "type": "query", + "description": "Enumerates all the DID, rev, and commit CID for all repos hosted by this service. Does not require auth; implemented by PDS and Relay.", + "parameters": { + "type": "params", + "properties": { + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 1000, + "default": 500 + }, + "cursor": { "type": "string" } + } + }, + "output": { + "encoding": "application/json", + "schema": { + "type": "object", + "required": ["repos"], + "properties": { + "cursor": { "type": "string" }, + "repos": { + "type": "array", + "items": { "type": "ref", "ref": "#repo" } + } + } + } + } + }, + "repo": { + "type": "object", + "required": ["did", "head", "rev"], + "properties": { + "did": { "type": "string", "format": "did" }, + "head": { + "type": "string", + "format": "cid", + "description": "Current repo commit CID" + }, + "rev": { "type": "string", "format": "tid" }, + "active": { "type": "boolean" }, + "status": { + "type": "string", + "description": "If active=false, this optional field indicates a possible reason for why the account is not active. If active=false and no status is supplied, then the host makes no claim for why the repository is no longer being hosted.", + "knownValues": [ + "takendown", + "suspended", + "deleted", + "deactivated", + "desynchronized", + "throttled" + ] + } + } + } + } +} diff --git a/lexicons/com/atproto/sync/subscribeRepos.json b/lexicons/com/atproto/sync/subscribeRepos.json new file mode 100644 index 000000000..373b050f2 --- /dev/null +++ b/lexicons/com/atproto/sync/subscribeRepos.json @@ -0,0 +1,215 @@ +{ + "lexicon": 1, + "id": "com.atproto.sync.subscribeRepos", + "defs": { + "main": { + "type": "subscription", + "description": "Repository event stream, aka Firehose endpoint. Outputs repo commits with diff data, and identity update events, for all repositories on the current server. See the atproto specifications for details around stream sequencing, repo versioning, CAR diff format, and more. Public and does not require auth; implemented by PDS and Relay.", + "parameters": { + "type": "params", + "properties": { + "cursor": { + "type": "integer", + "description": "The last known event seq number to backfill from." + } + } + }, + "message": { + "schema": { + "type": "union", + "refs": ["#commit", "#sync", "#identity", "#account", "#info"] + } + }, + "errors": [ + { "name": "FutureCursor" }, + { + "name": "ConsumerTooSlow", + "description": "If the consumer of the stream can not keep up with events, and a backlog gets too large, the server will drop the connection." + } + ] + }, + "commit": { + "type": "object", + "description": "Represents an update of repository state. Note that empty commits are allowed, which include no repo data changes, but an update to rev and signature.", + "required": [ + "seq", + "rebase", + "tooBig", + "repo", + "commit", + "rev", + "since", + "blocks", + "ops", + "blobs", + "time" + ], + "nullable": ["since"], + "properties": { + "seq": { + "type": "integer", + "description": "The stream sequence number of this message." + }, + "rebase": { "type": "boolean", "description": "DEPRECATED -- unused" }, + "tooBig": { + "type": "boolean", + "description": "DEPRECATED -- replaced by #sync event and data limits. Indicates that this commit contained too many ops, or data size was too large. Consumers will need to make a separate request to get missing data." + }, + "repo": { + "type": "string", + "format": "did", + "description": "The repo this event comes from. Note that all other message types name this field 'did'." + }, + "commit": { + "type": "cid-link", + "description": "Repo commit object CID." + }, + "rev": { + "type": "string", + "format": "tid", + "description": "The rev of the emitted commit. Note that this information is also in the commit object included in blocks, unless this is a tooBig event." + }, + "since": { + "type": "string", + "format": "tid", + "description": "The rev of the last emitted commit from this repo (if any)." + }, + "blocks": { + "type": "bytes", + "description": "CAR file containing relevant blocks, as a diff since the previous repo state. The commit must be included as a block, and the commit block CID must be the first entry in the CAR header 'roots' list.", + "maxLength": 2000000 + }, + "ops": { + "type": "array", + "items": { + "type": "ref", + "ref": "#repoOp", + "description": "List of repo mutation operations in this commit (eg, records created, updated, or deleted)." + }, + "maxLength": 200 + }, + "blobs": { + "type": "array", + "items": { + "type": "cid-link", + "description": "DEPRECATED -- will soon always be empty. List of new blobs (by CID) referenced by records in this commit." + } + }, + "prevData": { + "type": "cid-link", + "description": "The root CID of the MST tree for the previous commit from this repo (indicated by the 'since' revision field in this message). Corresponds to the 'data' field in the repo commit object. NOTE: this field is effectively required for the 'inductive' version of firehose." + }, + "time": { + "type": "string", + "format": "datetime", + "description": "Timestamp of when this message was originally broadcast." + } + } + }, + "sync": { + "type": "object", + "description": "Updates the repo to a new state, without necessarily including that state on the firehose. Used to recover from broken commit streams, data loss incidents, or in situations where upstream host does not know recent state of the repository.", + "required": ["seq", "did", "blocks", "rev", "time"], + "properties": { + "seq": { + "type": "integer", + "description": "The stream sequence number of this message." + }, + "did": { + "type": "string", + "format": "did", + "description": "The account this repo event corresponds to. Must match that in the commit object." + }, + "blocks": { + "type": "bytes", + "description": "CAR file containing the commit, as a block. The CAR header must include the commit block CID as the first 'root'.", + "maxLength": 10000 + }, + "rev": { + "type": "string", + "description": "The rev of the commit. This value must match that in the commit object." + }, + "time": { + "type": "string", + "format": "datetime", + "description": "Timestamp of when this message was originally broadcast." + } + } + }, + "identity": { + "type": "object", + "description": "Represents a change to an account's identity. Could be an updated handle, signing key, or pds hosting endpoint. Serves as a prod to all downstream services to refresh their identity cache.", + "required": ["seq", "did", "time"], + "properties": { + "seq": { "type": "integer" }, + "did": { "type": "string", "format": "did" }, + "time": { "type": "string", "format": "datetime" }, + "handle": { + "type": "string", + "format": "handle", + "description": "The current handle for the account, or 'handle.invalid' if validation fails. This field is optional, might have been validated or passed-through from an upstream source. Semantics and behaviors for PDS vs Relay may evolve in the future; see atproto specs for more details." + } + } + }, + "account": { + "type": "object", + "description": "Represents a change to an account's status on a host (eg, PDS or Relay). The semantics of this event are that the status is at the host which emitted the event, not necessarily that at the currently active PDS. Eg, a Relay takedown would emit a takedown with active=false, even if the PDS is still active.", + "required": ["seq", "did", "time", "active"], + "properties": { + "seq": { "type": "integer" }, + "did": { "type": "string", "format": "did" }, + "time": { "type": "string", "format": "datetime" }, + "active": { + "type": "boolean", + "description": "Indicates that the account has a repository which can be fetched from the host that emitted this event." + }, + "status": { + "type": "string", + "description": "If active=false, this optional field indicates a reason for why the account is not active.", + "knownValues": [ + "takendown", + "suspended", + "deleted", + "deactivated", + "desynchronized", + "throttled" + ] + } + } + }, + "info": { + "type": "object", + "required": ["name"], + "properties": { + "name": { + "type": "string", + "knownValues": ["OutdatedCursor"] + }, + "message": { + "type": "string" + } + } + }, + "repoOp": { + "type": "object", + "description": "A repo operation, ie a mutation of a single record.", + "required": ["action", "path", "cid"], + "nullable": ["cid"], + "properties": { + "action": { + "type": "string", + "knownValues": ["create", "update", "delete"] + }, + "path": { "type": "string" }, + "cid": { + "type": "cid-link", + "description": "For creates and updates, the new record CID. For deletions, null." + }, + "prev": { + "type": "cid-link", + "description": "For updates and deletes, the previous record CID (required for inductive firehose). For creations, field should not be defined." + } + } + } + } +} diff --git a/lexicons/lexicons.go b/lexicons/lexicons.go new file mode 100644 index 000000000..46101704d --- /dev/null +++ b/lexicons/lexicons.go @@ -0,0 +1,6 @@ +package lexicons + +import "embed" + +//go:embed all:**/* +var AllFiles embed.FS diff --git a/pkg/api/api.go b/pkg/api/api.go index 881519c6b..2899ba1c6 100644 --- a/pkg/api/api.go +++ b/pkg/api/api.go @@ -208,6 +208,7 @@ func (a *StreamplaceAPI) Handler(ctx context.Context) (http.Handler, error) { router.Handler("PATCH", "/xrpc/*resource", xrpcHandler) router.Handler("DELETE", "/xrpc/*resource", xrpcHandler) router.GET("/.well-known/did.json", a.HandleDidJSON(ctx)) + router.GET("/.well-known/atproto-did", a.HandleAtprotoDID(ctx)) router.GET("/dl/*params", a.HandleAppDownload(ctx)) router.POST("/", a.HandleWebRTCIngest(ctx)) for _, redirect := range a.CLI.Redirects { diff --git a/pkg/api/feeds.go b/pkg/api/feeds.go index a87dcf41b..296c98fd8 100644 --- a/pkg/api/feeds.go +++ b/pkg/api/feeds.go @@ -7,25 +7,14 @@ import ( "net/http" "github.com/julienschmidt/httprouter" + "stream.place/streamplace/pkg/atproto" "stream.place/streamplace/pkg/log" ) func (a *StreamplaceAPI) HandleDidJSON(ctx context.Context) httprouter.Handle { return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) { - host := req.Host - didJSON := map[string]any{ - "@context": []string{ - "https://www.w3.org/ns/did/v1", - }, - "id": fmt.Sprintf("did:web:%s", host), - "service": []map[string]any{ - { - "id": "#bsky_fg", - "type": "BskyFeedGenerator", - "serviceEndpoint": fmt.Sprintf("https://%s", host), - }, - }, - } + host := a.CLI.PublicHost + didJSON := atproto.DIDDoc(host) w.WriteHeader(200) w.Header().Set("Content-Type", "application/json") bs, err := json.Marshal(didJSON) @@ -38,3 +27,13 @@ func (a *StreamplaceAPI) HandleDidJSON(ctx context.Context) httprouter.Handle { } } } + +func (a *StreamplaceAPI) HandleAtprotoDID(ctx context.Context) httprouter.Handle { + return func(w http.ResponseWriter, req *http.Request, params httprouter.Params) { + host := a.CLI.PublicHost + _, err := fmt.Fprintf(w, "did:web:%s", host) + if err != nil { + log.Error(ctx, "error writing response", "error", err) + } + } +} diff --git a/pkg/atproto/atproto.go b/pkg/atproto/atproto.go index f14dd40ca..845ba6ba3 100644 --- a/pkg/atproto/atproto.go +++ b/pkg/atproto/atproto.go @@ -166,3 +166,37 @@ func resolveIdent(ctx context.Context, arg string) (*identity.Identity, error) { dir := identity.DefaultDirectory() return dir.Lookup(ctx, *id) } + +func DIDDoc(host string) map[string]any { + return map[string]any{ + "@context": []string{ + "https://www.w3.org/ns/did/v1", + "https://w3id.org/security/multikey/v1", + "https://w3id.org/security/suites/secp256k1-2019/v1", + }, + "id": fmt.Sprintf("did:web:%s", host), + "alsoKnownAs": []string{ + fmt.Sprintf("at://%s", host), + }, + "service": []map[string]any{ + { + "id": "#bsky_fg", + "type": "BskyFeedGenerator", + "serviceEndpoint": fmt.Sprintf("https://%s", host), + }, + { + "id": "#atproto_pds", + "type": "AtprotoPersonalDataServer", + "serviceEndpoint": fmt.Sprintf("https://%s", host), + }, + }, + "verificationMethod": []map[string]any{ + { + "id": fmt.Sprintf("did:web:%s#atproto", host), + "type": "Multikey", + "controller": fmt.Sprintf("did:web:%s", host), + "publicKeyMultibase": LexiconPubMultibase, + }, + }, + } +} diff --git a/pkg/atproto/atproto_test.go b/pkg/atproto/atproto_test.go index aa8448aff..0b2e99b73 100644 --- a/pkg/atproto/atproto_test.go +++ b/pkg/atproto/atproto_test.go @@ -3,55 +3,48 @@ package atproto import ( "context" "encoding/base64" - "encoding/json" - "os" - "path/filepath" "testing" - "github.com/bluesky-social/indigo/atproto/identity" "github.com/bluesky-social/indigo/xrpc" - "github.com/stretchr/testify/require" - "stream.place/streamplace/pkg/log" - "stream.place/streamplace/pkg/model" ) func TestKeyResolution(t *testing.T) { - dir, err := os.MkdirTemp("", "atproto-test-*") - require.NoError(t, err) - defer os.RemoveAll(dir) + // dir, err := os.MkdirTemp("", "atproto-test-*") + // require.NoError(t, err) + // defer os.RemoveAll(dir) - fname := filepath.Join(dir, "db.sqlite") - mod, err := model.MakeDB(fname) - require.NoError(t, err) - oldResolveIdent := ResolveIdent - ResolveIdent = func(ctx context.Context, arg string) (*identity.Identity, error) { - var doc identity.DIDDocument - err = json.Unmarshal(didDoc, &doc) - require.NoError(t, err) + // fname := filepath.Join(dir, "db.sqlite") + // mod, err := model.MakeDB(fname) + // require.NoError(t, err) + // oldResolveIdent := ResolveIdent + // ResolveIdent = func(ctx context.Context, arg string) (*identity.Identity, error) { + // var doc identity.DIDDocument + // err = json.Unmarshal(didDoc, &doc) + // require.NoError(t, err) - id := identity.ParseIdentity(&doc) - return &id, nil - } - defer func() { ResolveIdent = oldResolveIdent }() - oldSyncGetRepo := SyncGetRepo - defer func() { SyncGetRepo = oldSyncGetRepo }() + // id := identity.ParseIdentity(&doc) + // return &id, nil + // } + // defer func() { ResolveIdent = oldResolveIdent }() + // oldSyncGetRepo := SyncGetRepo + // defer func() { SyncGetRepo = oldSyncGetRepo }() - atsync := &ATProtoSynchronizer{ - Model: mod, - } + // atsync := &ATProtoSynchronizer{ + // Model: mod, + // } - ctx := log.WithDebugValue(context.Background(), map[string]map[string]int{ - "func": {"handleCreateUpdate": 9, "SyncBlueskyRepo": 9}, - }) + // ctx := log.WithDebugValue(context.Background(), map[string]map[string]int{ + // "func": {"handleCreateUpdate": 9, "SyncBlueskyRepo": 9}, + // }) - // full sync - SyncGetRepo = MockSyncGetRepo(fullSync) - repo, err := atsync.SyncBlueskyRepo(ctx, "streamplace-test", mod) - require.NoError(t, err) - keys, err := mod.GetSigningKeysForRepo(repo.DID) - require.NoError(t, err) - require.Len(t, keys, 1) - require.Equal(t, firstKey, keys[0].DID) + // // full sync + // SyncGetRepo = MockSyncGetRepo(fullSync) + // repo, err := atsync.SyncBlueskyRepo(ctx, "streamplace-test", mod) + // require.NoError(t, err) + // keys, err := mod.GetSigningKeysForRepo(repo.DID) + // require.NoError(t, err) + // require.Len(t, keys, 1) + // require.Equal(t, firstKey, keys[0].DID) // // incremental sync with no changes // SyncGetRepo = MockSyncGetRepo(incrementalSyncSameKey) diff --git a/pkg/atproto/get_cid.go b/pkg/atproto/get_cid.go new file mode 100644 index 000000000..7b08e5558 --- /dev/null +++ b/pkg/atproto/get_cid.go @@ -0,0 +1,23 @@ +package atproto + +import ( + "bytes" + + "github.com/bluesky-social/indigo/repo" + "github.com/ipfs/go-cid" + "github.com/multiformats/go-multihash" +) + +func GetCID(record repo.CborMarshaler) (*cid.Cid, error) { + builder := cid.NewPrefixV1(cid.DagCBOR, multihash.SHA2_256) + buf := bytes.NewBuffer(nil) + err := record.MarshalCBOR(buf) + if err != nil { + return nil, err + } + c, err := builder.Sum(buf.Bytes()) + if err != nil { + return nil, err + } + return &c, nil +} diff --git a/pkg/atproto/lexicon_repo.go b/pkg/atproto/lexicon_repo.go new file mode 100644 index 000000000..438523778 --- /dev/null +++ b/pkg/atproto/lexicon_repo.go @@ -0,0 +1,355 @@ +package atproto + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "io/fs" + "strings" + "time" + + comatproto "github.com/bluesky-social/indigo/api/atproto" + atcrypto "github.com/bluesky-social/indigo/atproto/crypto" + "github.com/bluesky-social/indigo/atproto/data" + "github.com/bluesky-social/indigo/atproto/lexicon" + "github.com/bluesky-social/indigo/carstore" + lexutil "github.com/bluesky-social/indigo/lex/util" + "github.com/bluesky-social/indigo/models" + "github.com/bluesky-social/indigo/mst" + atrepo "github.com/bluesky-social/indigo/repo" + "github.com/bluesky-social/indigo/util" + "github.com/ipfs/go-cid" + cbg "github.com/whyrusleeping/cbor-gen" + "gorm.io/driver/sqlite" + "gorm.io/gorm" + + "github.com/whyrusleeping/go-did" + "stream.place/streamplace/lexicons" + "stream.place/streamplace/pkg/config" + "stream.place/streamplace/pkg/log" + "stream.place/streamplace/pkg/model" +) + +var LexiconRepo *atrepo.Repo +var LexiconPubMultibase string +var RepoUser models.Uid = models.Uid(1) +var CarStore carstore.CarStore +var ActionCreate = "create" +var ActionUpdate = "update" +var ActionDelete = "delete" + +func walkLexicons(ctx context.Context, bundle fs.FS, path string) ([][]byte, error) { + ret := [][]byte{} + err := fs.WalkDir(bundle, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { + return nil + } + if !strings.HasSuffix(path, ".json") { + return nil + } + lex, err := fs.ReadFile(bundle, path) + if err != nil { + return err + } + ret = append(ret, lex) + return nil + }) + return ret, err +} + +type SchemaFileWrapper struct { + LexiconTypeID string `json:"$type,const=com.atproto.lexicon.schema" cborgen:"$type,const=com.atproto.lexicon.schema"` + SchemaFile lexicon.SchemaFile +} + +func (sfw *SchemaFileWrapper) MarshalCBOR(w io.Writer) error { + bs, err := json.Marshal(sfw.SchemaFile) + if err != nil { + return err + } + mapObj, err := data.UnmarshalJSON(bs) + if err != nil { + return err + } + mapObj["$type"] = "com.atproto.lexicon.schema" + cbs, err := data.MarshalCBOR(mapObj) + if err != nil { + return err + } + _, err = w.Write(cbs) + if err != nil { + return err + } + return nil +} + +func (sfw *SchemaFileWrapper) MarshalJSON() ([]byte, error) { + bs, err := json.Marshal(sfw.SchemaFile) + if err != nil { + return nil, err + } + mapObj, err := data.UnmarshalJSON(bs) + if err != nil { + return nil, err + } + mapObj["$type"] = "com.atproto.lexicon.schema" + bs, err = json.Marshal(mapObj) + if err != nil { + return nil, err + } + return bs, nil +} + +type SPKeyManager struct { + priv *did.PrivKey +} + +func (km *SPKeyManager) VerifyUserSignature(ctx context.Context, did string, sb []byte, sig []byte) error { + panic("NYI") +} + +func (km *SPKeyManager) SignForUser(ctx context.Context, did string, sb []byte) ([]byte, error) { + return km.priv.Sign(sb) +} + +var AllFiles fs.FS = lexicons.AllFiles + +type Closer interface { + Close() error +} + +func MakeLexiconRepo(ctx context.Context, cli *config.CLI, mod model.Model) (Closer, error) { + ctx = log.WithLogValues(ctx, "func", "MakeLexiconRepo") + fd, err := cli.DataFileCreate([]string{"carstore", "empty"}, true) + if err != nil { + return nil, err + } + sqlitePath := cli.DataFilePath([]string{"carstore", "meta.sqlite"}) + + db, err := gorm.Open(sqlite.Open(sqlitePath)) + if err != nil { + return nil, err + } + err = fd.Close() + if err != nil { + return nil, err + } + CarStore, err = carstore.NewCarStore(db, []string{ + cli.DataFilePath([]string{"carstore"}), + }) + if err != nil { + return nil, err + } + + sqlDB, err := db.DB() + if err != nil { + return nil, err + } + + var priv *atcrypto.PrivateKeyK256 + exists, err := cli.DataFileExists([]string{"carstore", "repo.key"}) + if err != nil { + return nil, err + } + if exists { + buf := bytes.Buffer{} + err := cli.DataFileRead([]string{"carstore", "repo.key"}, &buf) + if err != nil { + return nil, err + } + priv, err = atcrypto.ParsePrivateBytesK256(buf.Bytes()) + if err != nil { + return nil, err + } + } else { + priv, err = atcrypto.GeneratePrivateKeyK256() + if err != nil { + return nil, err + } + bs := priv.Bytes() + err = cli.DataFileWrite([]string{"carstore", "repo.key"}, bytes.NewReader(bs), true) + if err != nil { + return nil, err + } + } + + pub, err := priv.PublicKey() + if err != nil { + return nil, fmt.Errorf("failed to get public key from private key: %w", err) + } + + LexiconPubMultibase = pub.Multibase() + signer := func(ctx context.Context, did string, sb []byte) ([]byte, error) { + return priv.HashAndSign(sb) + } + + ses, err := CarStore.NewDeltaSession(ctx, RepoUser, nil) + if err != nil { + return nil, fmt.Errorf("failed to create delta session: %w", err) + } + + currentRoot, err := CarStore.GetUserRepoHead(ctx, RepoUser) + if err != nil { + return nil, fmt.Errorf("failed to get user repo head: %w", err) + } + currentRev := "" + + if currentRoot == cid.Undef { + LexiconRepo = atrepo.NewRepo(ctx, cli.MyDID(), ses) + } else { + LexiconRepo, err = atrepo.OpenRepo(ctx, ses, currentRoot) + if err != nil { + return nil, fmt.Errorf("failed to open repo: %w", err) + } + currentRev, err = CarStore.GetUserRepoRev(ctx, RepoUser) + if err != nil { + return nil, fmt.Errorf("failed to get user repo rev: %w", err) + } + } + + LexiconPubMultibase = pub.Multibase() + lexs, err := walkLexicons(ctx, AllFiles, "/") + if err != nil { + return nil, fmt.Errorf("failed to walk lexicon files: %w", err) + } + + ops := []*comatproto.SyncSubscribeRepos_RepoOp{} + + for _, lex := range lexs { + lexFile := lexicon.SchemaFile{} + err := json.Unmarshal(lex, &lexFile) + if err != nil { + return nil, err + } + if !strings.HasPrefix(lexFile.ID, "place.stream") { + continue + } + sfw := &SchemaFileWrapper{SchemaFile: lexFile} + rpath := fmt.Sprintf("com.atproto.lexicon.schema/%s", lexFile.ID) + newCid, err := GetCID(sfw) + if err != nil { + return nil, err + } + cidLink := lexutil.LexLink(*newCid) + + oldCid, _, err := LexiconRepo.GetRecord(ctx, rpath) + if errors.Is(err, mst.ErrNotFound) { + _, err = LexiconRepo.PutRecord(ctx, rpath, sfw) + if err != nil { + return nil, err + } + log.Debug(ctx, "created new lexicon record", "rpath", rpath, "cid", newCid.String()) + ops = append(ops, &comatproto.SyncSubscribeRepos_RepoOp{ + Action: ActionCreate, + Path: rpath, + Cid: &cidLink, + }) + } else if err != nil { + return nil, err + } else { + if newCid.Equals(oldCid) { + log.Debug(ctx, "new cid is the same as old cid, skipping lexicon record", "rpath", rpath, "cid", newCid.String()) + continue + } else { + log.Debug(ctx, "new cid is different from old cid, updating lexicon record", "rpath", rpath, "old", oldCid.String(), "new", newCid.String()) + _, err = LexiconRepo.UpdateRecord(ctx, rpath, sfw) + if err != nil { + return nil, err + } + oldLink := lexutil.LexLink(oldCid) + ops = append(ops, &comatproto.SyncSubscribeRepos_RepoOp{ + Action: ActionUpdate, + Path: rpath, + Prev: &oldLink, + Cid: &cidLink, + }) + } + } + currentRoot, currentRev, err = LexiconRepo.Commit(ctx, signer) + if err != nil { + return nil, fmt.Errorf("failed to commit: %w", err) + } + + log.Debug(ctx, "LexiconRepo committed", "cid", currentRoot.String(), "rev", currentRev) + } + blocks, err := ses.CloseWithRoot(ctx, currentRoot, currentRev) + if err != nil { + return nil, fmt.Errorf("failed to close delta session: %w", err) + } + signed := LexiconRepo.SignedCommit() + if len(ops) > 0 { + log.Log(ctx, "created new lexicon commit for changes", "did", signed.Did, "data", signed.Data, "prev", signed.Prev, "rev", signed.Rev) + commit := &comatproto.SyncSubscribeRepos_Commit{ + Repo: cli.MyDID(), + Blocks: blocks, + Rev: currentRev, + Commit: lexutil.LexLink(currentRoot), + Time: time.Now().Format(util.ISO8601), + Ops: ops, + TooBig: false, + } + err := mod.CreateCommitEvent(commit, signed.Data.String()) + if err != nil { + return nil, fmt.Errorf("failed to create commit event: %w", err) + } + } + + return sqlDB, nil +} + +func OpenLexiconRepo(ctx context.Context) (*atrepo.Repo, *carstore.DeltaSession, error) { + ses, err := CarStore.NewDeltaSession(ctx, RepoUser, nil) + if err != nil { + return nil, nil, fmt.Errorf("handleComAtprotoRepoListRecords: failed to create delta session: %w", err) + } + + base := ses.BaseCid() + if base == cid.Undef { + return nil, nil, fmt.Errorf("handleComAtprotoRepoListRecords: delta session has no base cid") + } + + r, err := atrepo.OpenRepo(ctx, ses, base) + if err != nil { + return nil, nil, fmt.Errorf("handleComAtprotoRepoListRecords: failed to open repo: %w", err) + } + return r, ses, nil +} + +// Get record that handles special-casing for com.atproto.lexicon.schema +func GetRecordCBOR(ctx context.Context, ses *carstore.DeltaSession, c cid.Cid, collection string, rkey string) (cbg.CBORMarshaler, error) { + b, err := ses.Get(ctx, c) + if err != nil { + return nil, fmt.Errorf("handleComAtprotoRepoListRecords: failed to get record for collection %q, rkey %q: %w", collection, rkey, err) + } + var val cbg.CBORMarshaler + if collection == "com.atproto.lexicon.schema" { + sfMap, err := data.UnmarshalCBOR(b.RawData()) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal schema file: %w", err) + } + jbs, err := json.Marshal(sfMap) + if err != nil { + return nil, fmt.Errorf("failed to marshal schema file: %w", err) + } + sf := lexicon.SchemaFile{} + err = json.Unmarshal(jbs, &sf) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal schema file: %w", err) + } + val = &SchemaFileWrapper{ + SchemaFile: sf, + } + } else { + val, err = lexutil.CborDecodeValue(b.RawData()) + if err != nil { + return nil, fmt.Errorf("failed to decode record: %w", err) + } + } + return val, nil +} diff --git a/pkg/atproto/lexicon_repo_test.go b/pkg/atproto/lexicon_repo_test.go new file mode 100644 index 000000000..628b403f0 --- /dev/null +++ b/pkg/atproto/lexicon_repo_test.go @@ -0,0 +1,109 @@ +package atproto + +import ( + "context" + "encoding/json" + "io/fs" + "testing" + "testing/fstest" + + "github.com/stretchr/testify/require" + "stream.place/streamplace/lexicons" + "stream.place/streamplace/pkg/config" + "stream.place/streamplace/pkg/model" +) + +func TestLexiconRepo(t *testing.T) { + cli := config.CLI{ + PublicHost: "example.com", + } + cli.DataDir = t.TempDir() + mod, err := model.MakeDB(":memory:") + require.NoError(t, err) + + // creating a new repo + handle, err := MakeLexiconRepo(context.Background(), &cli, mod) + require.NoError(t, err) + r, sess, err := OpenLexiconRepo(context.Background()) + require.NoError(t, err) + require.NotNil(t, r) + require.NotNil(t, sess) + c, _, err := r.GetRecord(context.Background(), "com.atproto.lexicon.schema/place.stream.chat.message") + require.NoError(t, err) + rec, err := GetRecordCBOR(context.Background(), sess, c, "com.atproto.lexicon.schema", "place.stream.chat.message") + require.NoError(t, err) + require.NotNil(t, rec) + handle.Close() + + evts, err := mod.GetCommitEventsSinceSeq(cli.MyDID(), 0) + require.NoError(t, err) + require.Len(t, evts, 1) + require.Equal(t, evts[0].RepoDID, cli.MyDID()) + + // opening an existing repo + handle, err = MakeLexiconRepo(context.Background(), &cli, mod) + require.NoError(t, err) + handle.Close() + + // Walk all files and build a map of file contents, modifying the first file + files := map[string]*fstest.MapFile{} + + err = fs.WalkDir(lexicons.AllFiles, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { + return nil + } + contents, err := lexicons.AllFiles.ReadFile(path) + if err != nil { + return err + } + if path == "place/stream/chat/message.json" { + // Modify the first file encountered (for example, append a newline) + data := map[string]any{} + err := json.Unmarshal(contents, &data) + if err != nil { + return err + } + data["defs"].(map[string]any)["main"].(map[string]any)["description"] = "Some kind of chat nonsense." + contents, err = json.Marshal(data) + if err != nil { + return err + } + } + info, err := d.Info() + if err != nil { + return err + } + files[path] = &fstest.MapFile{ + Data: contents, + Mode: 0444, + ModTime: info.ModTime(), + } + return nil + }) + require.NoError(t, err) + modifiedFS := fstest.MapFS{} + for k, v := range files { + modifiedFS[k] = v + } + AllFiles = modifiedFS + + // opening an existing repo with modified lexicon + handle, err = MakeLexiconRepo(context.Background(), &cli, mod) + require.NoError(t, err) + handle.Close() + + evts, err = mod.GetCommitEventsSinceSeq(cli.MyDID(), 0) + require.NoError(t, err) + require.Len(t, evts, 2) + require.Equal(t, evts[0].RepoDID, cli.MyDID()) + require.Equal(t, evts[1].RepoDID, cli.MyDID()) + oldCommit, err := evts[0].ToCommitEvent() + require.NoError(t, err) + newCommit, err := evts[1].ToCommitEvent() + require.NoError(t, err) + require.Equal(t, newCommit.Since, &oldCommit.Rev) + require.Equal(t, newCommit.PrevData.String(), evts[0].SignedData) +} diff --git a/pkg/cmd/streamplace.go b/pkg/cmd/streamplace.go index 958a8394d..7b5859939 100644 --- a/pkg/cmd/streamplace.go +++ b/pkg/cmd/streamplace.go @@ -247,6 +247,11 @@ func start(build *config.BuildFlags, platformJobs []jobFunc) error { if err != nil { return err } + handle, err := atproto.MakeLexiconRepo(ctx, &cli, mod) + if err != nil { + return err + } + defer handle.Close() var noter notifications.FirebaseNotifier if cli.FirebaseServiceAccount != "" { noter, err = notifications.MakeFirebaseNotifier(ctx, cli.FirebaseServiceAccount) diff --git a/pkg/config/config.go b/pkg/config/config.go index 68467edf0..360602c73 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -17,9 +17,10 @@ import ( "strings" "time" + "math/rand/v2" + "github.com/lestrrat-go/jwx/v2/jwk" "github.com/peterbourgon/ff/v3" - "golang.org/x/exp/rand" "stream.place/streamplace/pkg/aqtime" "stream.place/streamplace/pkg/constants" "stream.place/streamplace/pkg/crypto/aqpub" @@ -208,7 +209,7 @@ func RandomTrailer(length int) string { res := make([]byte, length) for i := 0; i < length; i++ { - res[i] = charset[rand.Intn(len(charset))] + res[i] = charset[rand.IntN(len(charset))] } return string(res) } @@ -451,3 +452,7 @@ func (cli *CLI) StreamIsAllowed(did string) error { } return fmt.Errorf("user is not allowed to stream") } + +func (cli *CLI) MyDID() string { + return fmt.Sprintf("did:web:%s", cli.PublicHost) +} diff --git a/pkg/model/model.go b/pkg/model/model.go index 378c69210..65502abfa 100644 --- a/pkg/model/model.go +++ b/pkg/model/model.go @@ -8,6 +8,7 @@ import ( "strings" "time" + comatproto "github.com/bluesky-social/indigo/api/atproto" "github.com/bluesky-social/indigo/api/bsky" "github.com/lmittmann/tint" slogGorm "github.com/orandin/slog-gorm" @@ -96,6 +97,11 @@ type Model interface { UpdateServerSettings(ctx context.Context, settings *ServerSettings) error GetServerSettings(ctx context.Context, server string, repoDID string) (*ServerSettings, error) DeleteServerSettings(ctx context.Context, server string, repoDID string) error + + CreateCommitEvent(commit *comatproto.SyncSubscribeRepos_Commit, signedData string) error + GetCommitEventsSince(repoDID string, t time.Time) ([]*XrpcStreamEvent, error) + GetCommitEventsSinceSeq(repoDID string, seq int64) ([]*XrpcStreamEvent, error) + GetMostRecentCommitEvent(repoDID string) (*XrpcStreamEvent, error) } func MakeDB(dbURL string) (Model, error) { @@ -156,6 +162,7 @@ func MakeDB(dbURL string) (Model, error) { ChatProfile{}, oatproxy.OAuthSession{}, ServerSettings{}, + XrpcStreamEvent{}, } { err = db.AutoMigrate(model) if err != nil { diff --git a/pkg/model/resync.go b/pkg/model/resync.go deleted file mode 100644 index 8b5379070..000000000 --- a/pkg/model/resync.go +++ /dev/null @@ -1 +0,0 @@ -package model diff --git a/pkg/model/xrpc_stream_event.go b/pkg/model/xrpc_stream_event.go new file mode 100644 index 000000000..b6fbacbdd --- /dev/null +++ b/pkg/model/xrpc_stream_event.go @@ -0,0 +1,108 @@ +package model + +import ( + "bytes" + "errors" + "time" + + comatproto "github.com/bluesky-social/indigo/api/atproto" + lexutil "github.com/bluesky-social/indigo/lex/util" + "github.com/bluesky-social/indigo/util" + "github.com/ipfs/go-cid" + "gorm.io/gorm" +) + +type XrpcStreamEvent struct { + CID string `json:"cid" gorm:"primaryKey"` + RepoDID string `json:"repoDID" gorm:"index:idx_repo_timestamp,priority:1;index:idx_repo_seq,priority:1;column:repo_did"` + Timestamp time.Time `json:"timestamp" gorm:"index:idx_repo_timestamp,priority:2;column:timestamp"` + Data []byte `json:"data"` + SignedData string `json:"signedData" gorm:"column:signed_data"` + Seq int64 `json:"seq" gorm:"index:idx_repo_seq,priority:2;column:seq"` +} + +func (ev *XrpcStreamEvent) ToCommitEvent() (*comatproto.SyncSubscribeRepos_Commit, error) { + commit := &comatproto.SyncSubscribeRepos_Commit{} + err := commit.UnmarshalCBOR(bytes.NewReader(ev.Data)) + if err != nil { + return nil, err + } + return commit, nil +} + +func (m *DBModel) CreateCommitEvent(commit *comatproto.SyncSubscribeRepos_Commit, signedData string) error { + prev, err := m.GetMostRecentCommitEvent(commit.Repo) + if err != nil { + return err + } + if prev != nil { + prevCommit, err := prev.ToCommitEvent() + if err != nil { + return err + } + commit.Seq = prevCommit.Seq + 1 + c, err := cid.Parse(prev.SignedData) + if err != nil { + return err + } + ll := lexutil.LexLink(c) + commit.PrevData = &ll + commit.Since = &prevCommit.Rev + } else { + commit.Seq = 1 + } + buf := bytes.Buffer{} + err = commit.MarshalCBOR(&buf) + if err != nil { + return err + } + timestamp, err := time.Parse(util.ISO8601, commit.Time) + if err != nil { + return err + } + event := &XrpcStreamEvent{ + CID: commit.Commit.String(), + RepoDID: commit.Repo, + Timestamp: timestamp.UTC(), + Data: buf.Bytes(), + Seq: commit.Seq, + SignedData: signedData, + } + return m.DB.Create(event).Error +} + +func (m *DBModel) GetCommitEventsSince(repoDID string, t time.Time) ([]*XrpcStreamEvent, error) { + var events []*XrpcStreamEvent + query := m.DB.Where("repo_did = ?", repoDID) + query = query.Where("timestamp > ?", t.UTC()) + err := query.Order("timestamp ASC").Find(&events).Error + if err != nil { + return nil, err + } + return events, nil +} + +func (m *DBModel) GetCommitEventsSinceSeq(repoDID string, seq int64) ([]*XrpcStreamEvent, error) { + var events []*XrpcStreamEvent + query := m.DB.Where("repo_did = ?", repoDID) + query = query.Where("seq > ?", seq) + err := query.Order("timestamp ASC").Find(&events).Error + if err != nil { + return nil, err + } + return events, nil +} + +func (m *DBModel) GetMostRecentCommitEvent(repoDID string) (*XrpcStreamEvent, error) { + var event XrpcStreamEvent + err := m.DB.Where("repo_did = ?", repoDID). + Order("timestamp DESC"). + Limit(1). + First(&event).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + return nil, nil + } else if err != nil { + return nil, err + } + return &event, nil +} diff --git a/pkg/spxrpc/com_atproto_repo.go b/pkg/spxrpc/com_atproto_repo.go index ee16010b6..65463b294 100644 --- a/pkg/spxrpc/com_atproto_repo.go +++ b/pkg/spxrpc/com_atproto_repo.go @@ -2,14 +2,19 @@ package spxrpc import ( "context" + "fmt" "io" "net/http" comatprototypes "github.com/bluesky-social/indigo/api/atproto" + lexutil "github.com/bluesky-social/indigo/lex/util" + "github.com/bluesky-social/indigo/xrpc" + "github.com/ipfs/go-cid" "github.com/labstack/echo/v4" "github.com/streamplace/oatproxy/pkg/oatproxy" "go.opentelemetry.io/otel" + "stream.place/streamplace/pkg/atproto" "stream.place/streamplace/pkg/log" ) @@ -24,7 +29,7 @@ func (s *Server) handleComAtprotoRepoUploadBlob(ctx context.Context, r io.Reader var out comatprototypes.RepoUploadBlob_Output - var xrpcType xrpc.XRPCRequestType + var xrpcType string var err error xrpcType = xrpc.Procedure err = client.Do(ctx, xrpcType, contentType, "com.atproto.repo.uploadBlob", nil, r, &out) @@ -36,3 +41,63 @@ func (s *Server) handleComAtprotoRepoUploadBlob(ctx context.Context, r io.Reader return &out, nil } + +func (s *Server) handleComAtprotoRepoDescribeRepo(ctx context.Context, repo string) (*comatprototypes.RepoDescribeRepo_Output, error) { + return &comatprototypes.RepoDescribeRepo_Output{ + Handle: s.cli.PublicHost, + Did: fmt.Sprintf("did:web:%s", s.cli.PublicHost), + DidDoc: atproto.DIDDoc(s.cli.PublicHost), + Collections: []string{ + "com.atproto.lexicon.schema", + }, + HandleIsCorrect: true, + }, nil +} + +func (s *Server) handleComAtprotoRepoListRecords(ctx context.Context, collection string, cursor string, limit int, repo string, reverse *bool) (*comatprototypes.RepoListRecords_Output, error) { + r, ses, err := atproto.OpenLexiconRepo(ctx) + if err != nil { + return nil, fmt.Errorf("handleComAtprotoRepoListRecords: failed to open repo: %w", err) + } + out := &comatprototypes.RepoListRecords_Output{ + Records: []*comatprototypes.RepoListRecords_Record{}, + } + err = r.ForEach(ctx, "", func(rkey string, c cid.Cid) error { + val, err := atproto.GetRecordCBOR(ctx, ses, c, collection, rkey) + if err != nil { + return fmt.Errorf("handleComAtprotoRepoListRecords: failed to get record for collection %q, rkey %q: %w", collection, rkey, err) + } + out.Records = append(out.Records, &comatprototypes.RepoListRecords_Record{ + Uri: fmt.Sprintf("at://%s/%s/%s", repo, collection, rkey), + Cid: c.String(), + Value: &lexutil.LexiconTypeDecoder{Val: val}, + }) + + return nil + }) + if err != nil { + return nil, fmt.Errorf("handleComAtprotoRepoListRecords: error iterating records for collection %q: %w", collection, err) + } + return out, nil +} + +func (s *Server) handleComAtprotoRepoGetRecord(ctx context.Context, c string, collection string, repo string, rkey string) (*comatprototypes.RepoGetRecord_Output, error) { + r, ses, err := atproto.OpenLexiconRepo(ctx) + if err != nil { + return nil, fmt.Errorf("handleComAtprotoRepoGetRecord: failed to open repo: %w", err) + } + outCID, _, err := r.GetRecord(ctx, fmt.Sprintf("%s/%s", collection, rkey)) + if err != nil { + return nil, err + } + rec, err := atproto.GetRecordCBOR(ctx, ses, outCID, collection, rkey) + if err != nil { + return nil, fmt.Errorf("handleComAtprotoRepoGetRecord: failed to get record: %w", err) + } + str := outCID.String() + return &comatprototypes.RepoGetRecord_Output{ + Uri: fmt.Sprintf("at://%s/%s/%s", repo, collection, rkey), + Cid: &str, + Value: &lexutil.LexiconTypeDecoder{Val: rec}, + }, nil +} diff --git a/pkg/spxrpc/com_atproto_server.go b/pkg/spxrpc/com_atproto_server.go new file mode 100644 index 000000000..8da207dd0 --- /dev/null +++ b/pkg/spxrpc/com_atproto_server.go @@ -0,0 +1,20 @@ +package spxrpc + +import ( + "context" + "fmt" + + comatprototypes "github.com/bluesky-social/indigo/api/atproto" +) + +func (s *Server) handleComAtprotoServerDescribeServer(ctx context.Context) (*comatprototypes.ServerDescribeServer_Output, error) { + did := fmt.Sprintf("did:web:%s", s.cli.PublicHost) + trueVar := true + return &comatprototypes.ServerDescribeServer_Output{ + Did: did, + InviteCodeRequired: &trueVar, + AvailableUserDomains: []string{ + fmt.Sprintf(".%s", s.cli.PublicHost), + }, + }, nil +} diff --git a/pkg/spxrpc/com_atproto_sync.go b/pkg/spxrpc/com_atproto_sync.go new file mode 100644 index 000000000..5dedb938b --- /dev/null +++ b/pkg/spxrpc/com_atproto_sync.go @@ -0,0 +1,152 @@ +package spxrpc + +import ( + "bytes" + "context" + "fmt" + "io" + "net/http" + "strconv" + + comatprototypes "github.com/bluesky-social/indigo/api/atproto" + "github.com/bluesky-social/indigo/carstore" + "github.com/bluesky-social/indigo/events" + "github.com/bluesky-social/indigo/repo" + "github.com/bluesky-social/indigo/util" + "github.com/gorilla/websocket" + "github.com/ipfs/go-cid" + cbor "github.com/ipfs/go-ipld-cbor" + "github.com/ipld/go-car" + "github.com/labstack/echo/v4" + "stream.place/streamplace/pkg/atproto" + "stream.place/streamplace/pkg/log" +) + +func (s *Server) handleComAtprotoSyncListRepos(ctx context.Context, cursor string, limit int) (*comatprototypes.SyncListRepos_Output, error) { + active := true + return &comatprototypes.SyncListRepos_Output{ + Repos: []*comatprototypes.SyncListRepos_Repo{ + { + Did: atproto.LexiconRepo.RepoDid(), + Head: atproto.LexiconRepo.SignedCommit().Data.String(), + Rev: atproto.LexiconRepo.SignedCommit().Rev, + Active: &active, + }, + }, + }, nil +} + +func (s *Server) handleComAtprotoSyncGetRecord(ctx context.Context, collection string, did string, rkey string) (io.Reader, error) { + _, robs, err := atproto.OpenLexiconRepo(ctx) + if err != nil { + return nil, fmt.Errorf("handleComAtprotoRepoGetRecord: failed to open repo: %w", err) + } + + bs := util.NewLoggingBstore(robs) + + root, err := atproto.CarStore.GetUserRepoHead(ctx, atproto.RepoUser) + if err != nil { + return nil, fmt.Errorf("handleComAtprotoRepoGetRecord: failed to get user repo head: %w", err) + } + + r, err := repo.OpenRepo(ctx, bs, root) + if err != nil { + return nil, fmt.Errorf("handleComAtprotoRepoGetRecord: failed to open repo: %w", err) + } + + _, _, err = r.GetRecordBytes(ctx, collection+"/"+rkey) + if err != nil { + return nil, fmt.Errorf("handleComAtprotoRepoGetRecord: failed to get record bytes: %w", err) + } + + blocks := bs.GetLoggedBlocks() + + buf := new(bytes.Buffer) + hb, err := cbor.DumpObject(&car.CarHeader{ + Roots: []cid.Cid{root}, + Version: 1, + }) + if err != nil { + return nil, fmt.Errorf("failed to dump car header: %w", err) + } + if _, err := carstore.LdWrite(buf, hb); err != nil { + return nil, err + } + + for _, blk := range blocks { + if _, err := carstore.LdWrite(buf, blk.Cid().Bytes(), blk.RawData()); err != nil { + return nil, err + } + } + + return bytes.NewReader(buf.Bytes()), nil +} + +var upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + CheckOrigin: func(r *http.Request) bool { + return true + }, +} + +func (s *Server) handleComAtprotoSyncSubscribeRepos(c echo.Context) error { + ctx := log.WithLogValues(c.Request().Context(), "client_ip", c.RealIP(), "user_agent", c.Request().UserAgent()) + cursor := c.QueryParam("cursor") + + if cursor == "" { + cursor = "0" + } + + seq, err := strconv.Atoi(cursor) + if err != nil { + return err + } + + conn, err := upgrader.Upgrade(c.Response(), c.Request(), nil) + if err != nil { + return err + } + + evts, err := s.model.GetCommitEventsSinceSeq(atproto.LexiconRepo.RepoDid(), int64(seq)) + if err != nil { + return err + } + + log.Log(ctx, "got com.atproto.sync.subscribeRepos", "cursor", c.QueryParam("cursor"), "eventCount", len(evts)) + + header := events.EventHeader{Op: events.EvtKindMessage} + for _, evt := range evts { + commit, err := evt.ToCommitEvent() + if err != nil { + return err + } + + wc, err := conn.NextWriter(websocket.BinaryMessage) + if err != nil { + return err + } + header.MsgType = "#commit" + + if err := header.MarshalCBOR(wc); err != nil { + return fmt.Errorf("failed to write header: %w", err) + } + + if err := commit.MarshalCBOR(wc); err != nil { + return fmt.Errorf("failed to write event: %w", err) + } + + if err := wc.Close(); err != nil { + return fmt.Errorf("failed to flush-close our event write: %w", err) + } + } + + // We don't have anything else to do but we'll keep the socket open until the client disconnects + for { + _, _, err = conn.ReadMessage() + if err != nil { + log.Log(c.Request().Context(), "client disconnected", "error", err) + return nil + } + } +} diff --git a/pkg/spxrpc/place_stream_live.go b/pkg/spxrpc/place_stream_live.go index d95654d24..a44b2d950 100644 --- a/pkg/spxrpc/place_stream_live.go +++ b/pkg/spxrpc/place_stream_live.go @@ -1,17 +1,14 @@ package spxrpc import ( - "bytes" "context" "fmt" "net/http" "time" "github.com/bluesky-social/indigo/lex/util" - "github.com/bluesky-social/indigo/repo" - "github.com/ipfs/go-cid" "github.com/labstack/echo/v4" - "github.com/multiformats/go-multihash" + "stream.place/streamplace/pkg/atproto" "stream.place/streamplace/pkg/spmetrics" placestreamtypes "stream.place/streamplace/pkg/streamplace" @@ -45,7 +42,7 @@ func (s *Server) handlePlaceStreamLiveGetSegments(ctx context.Context, before st if err != nil { return nil, echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to convert segment to streamplace segment: %s", err)) } - c, err := getCID(record) + c, err := atproto.GetCID(record) if err != nil { return nil, echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf("Failed to get CID: %s", err)) } @@ -95,17 +92,3 @@ func (s *Server) handlePlaceStreamLiveGetLiveUsers(ctx context.Context, before s return liveUsers, nil } - -func getCID(record repo.CborMarshaler) (*cid.Cid, error) { - builder := cid.NewPrefixV1(cid.DagCBOR, multihash.SHA2_256) - buf := bytes.NewBuffer(nil) - err := record.MarshalCBOR(buf) - if err != nil { - return nil, err - } - c, err := builder.Sum(buf.Bytes()) - if err != nil { - return nil, err - } - return &c, nil -} diff --git a/pkg/spxrpc/spxrpc.go b/pkg/spxrpc/spxrpc.go index 5aa307589..071e678ef 100644 --- a/pkg/spxrpc/spxrpc.go +++ b/pkg/spxrpc/spxrpc.go @@ -41,6 +41,10 @@ func NewServer(ctx context.Context, cli *config.CLI, model model.Model, op *oatp if err != nil { return nil, err } + e.GET("/xrpc/_health", func(c echo.Context) error { + return c.JSON(http.StatusOK, map[string]string{"version": cli.Build.Version}) + }) + e.GET("/xrpc/com.atproto.sync.subscribeRepos", s.handleComAtprotoSyncSubscribeRepos) e.GET("/xrpc/*", s.HandleWildcard) e.POST("/xrpc/*", s.HandleWildcard) return s, nil diff --git a/pkg/spxrpc/stubs.go b/pkg/spxrpc/stubs.go index 92e4b1c07..8b1410bf0 100644 --- a/pkg/spxrpc/stubs.go +++ b/pkg/spxrpc/stubs.go @@ -1,6 +1,7 @@ package spxrpc import ( + "io" "strconv" comatprototypes "github.com/bluesky-social/indigo/api/atproto" @@ -62,7 +63,13 @@ func (s *Server) RegisterHandlersChatBsky(e *echo.Echo) error { func (s *Server) RegisterHandlersComAtproto(e *echo.Echo) error { e.GET("/xrpc/com.atproto.identity.resolveHandle", s.HandleComAtprotoIdentityResolveHandle) + e.GET("/xrpc/com.atproto.repo.describeRepo", s.HandleComAtprotoRepoDescribeRepo) + e.GET("/xrpc/com.atproto.repo.getRecord", s.HandleComAtprotoRepoGetRecord) + e.GET("/xrpc/com.atproto.repo.listRecords", s.HandleComAtprotoRepoListRecords) e.POST("/xrpc/com.atproto.repo.uploadBlob", s.HandleComAtprotoRepoUploadBlob) + e.GET("/xrpc/com.atproto.server.describeServer", s.HandleComAtprotoServerDescribeServer) + e.GET("/xrpc/com.atproto.sync.getRecord", s.HandleComAtprotoSyncGetRecord) + e.GET("/xrpc/com.atproto.sync.listRepos", s.HandleComAtprotoSyncListRepos) return nil } @@ -80,6 +87,73 @@ func (s *Server) HandleComAtprotoIdentityResolveHandle(c echo.Context) error { return c.JSON(200, out) } +func (s *Server) HandleComAtprotoRepoDescribeRepo(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoRepoDescribeRepo") + defer span.End() + repo := c.QueryParam("repo") + var out *comatprototypes.RepoDescribeRepo_Output + var handleErr error + // func (s *Server) handleComAtprotoRepoDescribeRepo(ctx context.Context,repo string) (*comatprototypes.RepoDescribeRepo_Output, error) + out, handleErr = s.handleComAtprotoRepoDescribeRepo(ctx, repo) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) HandleComAtprotoRepoGetRecord(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoRepoGetRecord") + defer span.End() + cid := c.QueryParam("cid") + collection := c.QueryParam("collection") + repo := c.QueryParam("repo") + rkey := c.QueryParam("rkey") + var out *comatprototypes.RepoGetRecord_Output + var handleErr error + // func (s *Server) handleComAtprotoRepoGetRecord(ctx context.Context,cid string,collection string,repo string,rkey string) (*comatprototypes.RepoGetRecord_Output, error) + out, handleErr = s.handleComAtprotoRepoGetRecord(ctx, cid, collection, repo, rkey) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) HandleComAtprotoRepoListRecords(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoRepoListRecords") + defer span.End() + collection := c.QueryParam("collection") + cursor := c.QueryParam("cursor") + + var limit int + if p := c.QueryParam("limit"); p != "" { + var err error + limit, err = strconv.Atoi(p) + if err != nil { + return err + } + } else { + limit = 50 + } + repo := c.QueryParam("repo") + + var reverse *bool + if p := c.QueryParam("reverse"); p != "" { + reverse_val, err := strconv.ParseBool(p) + if err != nil { + return err + } + reverse = &reverse_val + } + var out *comatprototypes.RepoListRecords_Output + var handleErr error + // func (s *Server) handleComAtprotoRepoListRecords(ctx context.Context,collection string,cursor string,limit int,repo string,reverse *bool) (*comatprototypes.RepoListRecords_Output, error) + out, handleErr = s.handleComAtprotoRepoListRecords(ctx, collection, cursor, limit, repo, reverse) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + func (s *Server) HandleComAtprotoRepoUploadBlob(c echo.Context) error { ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoRepoUploadBlob") defer span.End() @@ -95,6 +169,60 @@ func (s *Server) HandleComAtprotoRepoUploadBlob(c echo.Context) error { return c.JSON(200, out) } +func (s *Server) HandleComAtprotoServerDescribeServer(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoServerDescribeServer") + defer span.End() + var out *comatprototypes.ServerDescribeServer_Output + var handleErr error + // func (s *Server) handleComAtprotoServerDescribeServer(ctx context.Context) (*comatprototypes.ServerDescribeServer_Output, error) + out, handleErr = s.handleComAtprotoServerDescribeServer(ctx) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + +func (s *Server) HandleComAtprotoSyncGetRecord(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoSyncGetRecord") + defer span.End() + collection := c.QueryParam("collection") + did := c.QueryParam("did") + rkey := c.QueryParam("rkey") + var out io.Reader + var handleErr error + // func (s *Server) handleComAtprotoSyncGetRecord(ctx context.Context,collection string,did string,rkey string) (io.Reader, error) + out, handleErr = s.handleComAtprotoSyncGetRecord(ctx, collection, did, rkey) + if handleErr != nil { + return handleErr + } + return c.Stream(200, "application/vnd.ipld.car", out) +} + +func (s *Server) HandleComAtprotoSyncListRepos(c echo.Context) error { + ctx, span := otel.Tracer("server").Start(c.Request().Context(), "HandleComAtprotoSyncListRepos") + defer span.End() + cursor := c.QueryParam("cursor") + + var limit int + if p := c.QueryParam("limit"); p != "" { + var err error + limit, err = strconv.Atoi(p) + if err != nil { + return err + } + } else { + limit = 500 + } + var out *comatprototypes.SyncListRepos_Output + var handleErr error + // func (s *Server) handleComAtprotoSyncListRepos(ctx context.Context,cursor string,limit int) (*comatprototypes.SyncListRepos_Output, error) + out, handleErr = s.handleComAtprotoSyncListRepos(ctx, cursor, limit) + if handleErr != nil { + return handleErr + } + return c.JSON(200, out) +} + func (s *Server) RegisterHandlersPlaceStream(e *echo.Echo) error { e.GET("/xrpc/place.stream.graph.getFollowingUser", s.HandlePlaceStreamGraphGetFollowingUser) e.GET("/xrpc/place.stream.live.getLiveUsers", s.HandlePlaceStreamLiveGetLiveUsers) diff --git a/pkg/spxrpc/wildcard.go b/pkg/spxrpc/wildcard.go index e80826308..348019c91 100644 --- a/pkg/spxrpc/wildcard.go +++ b/pkg/spxrpc/wildcard.go @@ -28,7 +28,7 @@ func (s *Server) HandleWildcard(c echo.Context) error { segments := strings.Split(path, "/") lastSegment := segments[len(segments)-1] - var xrpcType xrpc.XRPCRequestType + var xrpcType string var err error if c.Request().Method == "GET" { xrpcType = xrpc.Query diff --git a/pkg/streamplace/graphgetFollowingUser.go b/pkg/streamplace/graphgetFollowingUser.go index 4073c8fd3..41696fd42 100644 --- a/pkg/streamplace/graphgetFollowingUser.go +++ b/pkg/streamplace/graphgetFollowingUser.go @@ -8,7 +8,7 @@ import ( "context" comatprototypes "github.com/bluesky-social/indigo/api/atproto" - "github.com/bluesky-social/indigo/xrpc" + "github.com/bluesky-social/indigo/lex/util" ) // GraphGetFollowingUser_Output is the output of a place.stream.graph.getFollowingUser call. @@ -20,14 +20,13 @@ type GraphGetFollowingUser_Output struct { // // subjectDID: The DID of the user potentially being followed // userDID: The DID of the potentially-following user -func GraphGetFollowingUser(ctx context.Context, c *xrpc.Client, subjectDID string, userDID string) (*GraphGetFollowingUser_Output, error) { +func GraphGetFollowingUser(ctx context.Context, c util.LexClient, subjectDID string, userDID string) (*GraphGetFollowingUser_Output, error) { var out GraphGetFollowingUser_Output - params := map[string]interface{}{ - "subjectDID": subjectDID, - "userDID": userDID, - } - if err := c.Do(ctx, xrpc.Query, "", "place.stream.graph.getFollowingUser", params, nil, &out); err != nil { + params := map[string]interface{}{} + params["subjectDID"] = subjectDID + params["userDID"] = userDID + if err := c.LexDo(ctx, util.Query, "", "place.stream.graph.getFollowingUser", params, nil, &out); err != nil { return nil, err } diff --git a/pkg/streamplace/livegetLiveUsers.go b/pkg/streamplace/livegetLiveUsers.go index a68f9e224..8feeb9c42 100644 --- a/pkg/streamplace/livegetLiveUsers.go +++ b/pkg/streamplace/livegetLiveUsers.go @@ -7,7 +7,7 @@ package streamplace import ( "context" - "github.com/bluesky-social/indigo/xrpc" + "github.com/bluesky-social/indigo/lex/util" ) // LiveGetLiveUsers_Output is the output of a place.stream.live.getLiveUsers call. @@ -16,14 +16,17 @@ type LiveGetLiveUsers_Output struct { } // LiveGetLiveUsers calls the XRPC method "place.stream.live.getLiveUsers". -func LiveGetLiveUsers(ctx context.Context, c *xrpc.Client, before string, limit int64) (*LiveGetLiveUsers_Output, error) { +func LiveGetLiveUsers(ctx context.Context, c util.LexClient, before string, limit int64) (*LiveGetLiveUsers_Output, error) { var out LiveGetLiveUsers_Output - params := map[string]interface{}{ - "before": before, - "limit": limit, + params := map[string]interface{}{} + if before != "" { + params["before"] = before } - if err := c.Do(ctx, xrpc.Query, "", "place.stream.live.getLiveUsers", params, nil, &out); err != nil { + if limit != 0 { + params["limit"] = limit + } + if err := c.LexDo(ctx, util.Query, "", "place.stream.live.getLiveUsers", params, nil, &out); err != nil { return nil, err } diff --git a/pkg/streamplace/livegetSegments.go b/pkg/streamplace/livegetSegments.go index 9ed56df74..97e2d17d8 100644 --- a/pkg/streamplace/livegetSegments.go +++ b/pkg/streamplace/livegetSegments.go @@ -7,7 +7,7 @@ package streamplace import ( "context" - "github.com/bluesky-social/indigo/xrpc" + "github.com/bluesky-social/indigo/lex/util" ) // LiveGetSegments_Output is the output of a place.stream.live.getSegments call. @@ -18,15 +18,18 @@ type LiveGetSegments_Output struct { // LiveGetSegments calls the XRPC method "place.stream.live.getSegments". // // userDID: The DID of the potentially-following user -func LiveGetSegments(ctx context.Context, c *xrpc.Client, before string, limit int64, userDID string) (*LiveGetSegments_Output, error) { +func LiveGetSegments(ctx context.Context, c util.LexClient, before string, limit int64, userDID string) (*LiveGetSegments_Output, error) { var out LiveGetSegments_Output - params := map[string]interface{}{ - "before": before, - "limit": limit, - "userDID": userDID, + params := map[string]interface{}{} + if before != "" { + params["before"] = before } - if err := c.Do(ctx, xrpc.Query, "", "place.stream.live.getSegments", params, nil, &out); err != nil { + if limit != 0 { + params["limit"] = limit + } + params["userDID"] = userDID + if err := c.LexDo(ctx, util.Query, "", "place.stream.live.getSegments", params, nil, &out); err != nil { return nil, err } diff --git a/pkg/streamplace/streamlivestream.go b/pkg/streamplace/streamlivestream.go index a480a2b25..3c7d3b9ec 100644 --- a/pkg/streamplace/streamlivestream.go +++ b/pkg/streamplace/streamlivestream.go @@ -24,7 +24,7 @@ type Livestream struct { // post: The post that announced this livestream. Post *comatprototypes.RepoStrongRef `json:"post,omitempty" cborgen:"post,omitempty"` Thumb *util.LexBlob `json:"thumb,omitempty" cborgen:"thumb,omitempty"` - // title: The title of the livestream, as it will be announced to followers. + // title: The title of the livestream, as it will be announced to followers! Title string `json:"title" cborgen:"title"` // url: The URL where this stream can be found. This is primarily a hint for other Streamplace nodes to locate and replicate the stream. Url *string `json:"url,omitempty" cborgen:"url,omitempty"`