Skip to content

Commit

Permalink
feat: expose routing v1 server via optional setting
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed Aug 8, 2023
1 parent b8e3930 commit 0805ab6
Show file tree
Hide file tree
Showing 20 changed files with 369 additions and 196 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Kubo Changelogs

- [v0.23](docs/changelogs/v0.23.md)
- [v0.22](docs/changelogs/v0.22.md)
- [v0.21](docs/changelogs/v0.21.md)
- [v0.20](docs/changelogs/v0.20.md)
Expand Down
4 changes: 4 additions & 0 deletions cmd/ipfs/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,10 @@ func serveHTTPGateway(req *cmds.Request, cctx *oldcmds.Context) (<-chan error, e
opts = append(opts, corehttp.P2PProxyOption())
}

if cfg.Gateway.ExposeRoutingAPI.WithDefault(config.DefaultExposeRoutingAPI) {
opts = append(opts, corehttp.RoutingOption())
}

if len(cfg.Gateway.RootRedirect) > 0 {
opts = append(opts, corehttp.RedirectOption("", cfg.Gateway.RootRedirect))
}
Expand Down
5 changes: 5 additions & 0 deletions config/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
const (
DefaultInlineDNSLink = false
DefaultDeserializedResponses = true
DefaultExposeRoutingAPI = false
)

type GatewaySpec struct {
Expand Down Expand Up @@ -73,4 +74,8 @@ type Gateway struct {
// PublicGateways configures behavior of known public gateways.
// Each key is a fully qualified domain name (FQDN).
PublicGateways map[string]*GatewaySpec

// ExposeRoutingAPI configures the gateway to expose a Routing v1 HTTP Server
// under /routing/v1: https://specs.ipfs.tech/routing/routing-v1/.
ExposeRoutingAPI Flag
}
18 changes: 0 additions & 18 deletions config/routing.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package config
import (
"encoding/json"
"fmt"
"runtime"
)

// Routing defines configuration options for libp2p routing
Expand Down Expand Up @@ -133,23 +132,6 @@ var MethodNameList = []MethodName{MethodNameProvide, MethodNameFindPeers, Method
type HTTPRouterParams struct {
// Endpoint is the URL where the routing implementation will point to get the information.
Endpoint string

// MaxProvideBatchSize determines the maximum amount of CIDs sent per batch.
// Servers might not accept more than 100 elements per batch. 100 elements by default.
MaxProvideBatchSize int

// MaxProvideConcurrency determines the number of threads used when providing content. GOMAXPROCS by default.
MaxProvideConcurrency int
}

func (hrp *HTTPRouterParams) FillDefaults() {
if hrp.MaxProvideBatchSize == 0 {
hrp.MaxProvideBatchSize = 100
}

if hrp.MaxProvideConcurrency == 0 {
hrp.MaxProvideConcurrency = runtime.GOMAXPROCS(0)
}
}

type DHTRouterParams struct {
Expand Down
124 changes: 124 additions & 0 deletions core/corehttp/routing.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package corehttp

import (
"context"
"net"
"net/http"

"github.com/ipfs/boxo/ipns"
"github.com/ipfs/boxo/routing/http/server"
"github.com/ipfs/boxo/routing/http/types"
"github.com/ipfs/boxo/routing/http/types/iter"
cid "github.com/ipfs/go-cid"
core "github.com/ipfs/kubo/core"
"github.com/libp2p/go-libp2p/core/peer"
)

func RoutingOption() ServeOption {
return func(n *core.IpfsNode, _ net.Listener, mux *http.ServeMux) (*http.ServeMux, error) {
handler := server.Handler(&contentRouter{n})
mux.Handle("/routing/v1/", handler)
return mux, nil
}
}

type contentRouter struct {
n *core.IpfsNode
}

func (r *contentRouter) GetProviders(ctx context.Context, key cid.Cid, limit int) (iter.ResultIter[types.Record], error) {
ctx, cancel := context.WithCancel(ctx)
ch := r.n.Routing.FindProvidersAsync(ctx, key, limit)
return iter.ToResultIter[types.Record](&peerChanIter{
ch: ch,
cancel: cancel,
}), nil
}

func (r *contentRouter) GetPeers(ctx context.Context, pid peer.ID, limit int) (iter.ResultIter[types.Record], error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()

addr, err := r.n.Routing.FindPeer(ctx, pid)
if err != nil {
return nil, err
}

rec := &types.PeerRecord{
Schema: types.SchemaPeer,
ID: &addr.ID,
}

for _, addr := range addr.Addrs {
rec.Addrs = append(rec.Addrs, types.Multiaddr{Multiaddr: addr})
}

return iter.ToResultIter[types.Record](iter.FromSlice[types.Record]([]types.Record{rec})), nil
}

func (r *contentRouter) GetIPNSRecord(ctx context.Context, name ipns.Name) (*ipns.Record, error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()

raw, err := r.n.Routing.GetValue(ctx, string(name.RoutingKey()))
if err != nil {
return nil, err
}

return ipns.UnmarshalRecord(raw)
}

func (r *contentRouter) PutIPNSRecord(ctx context.Context, name ipns.Name, record *ipns.Record) error {
ctx, cancel := context.WithCancel(ctx)
defer cancel()

raw, err := ipns.MarshalRecord(record)
if err != nil {
return err
}

// The caller guarantees that name matches the record. This is double checked
// by the internals of PutValue.
return r.n.Routing.PutValue(ctx, string(name.RoutingKey()), raw)
}

type peerChanIter struct {
ch <-chan peer.AddrInfo
cancel context.CancelFunc
next *peer.AddrInfo
}

func (it *peerChanIter) Next() bool {
addr, ok := <-it.ch
if ok {
it.next = &addr
return true
} else {
it.next = nil
return false
}
}

func (it *peerChanIter) Val() types.Record {
if it.next == nil {
return nil
}

// We don't know what type of protocol this peer provides. It is likely Bitswap
// but it might not be. Therefore, we set an unknown protocol with an unknown schema.
rec := &types.PeerRecord{
Schema: types.SchemaPeer,
ID: &it.next.ID,
}

for _, addr := range it.next.Addrs {
rec.Addrs = append(rec.Addrs, types.Multiaddr{Multiaddr: addr})
}

return rec
}

func (it *peerChanIter) Close() error {
it.cancel()
return nil
}
6 changes: 1 addition & 5 deletions core/node/libp2p/routingopt.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,7 @@ func ConstructDelegatedRouting(routers config.Routers, methods config.Methods, p
Datastore: args.Datastore,
Context: args.Ctx,
},
&irouting.ExtraHTTPParams{
PeerID: peerID,
Addrs: httpAddrsFromConfig(addrs),
PrivKeyB64: privKey,
})
)
}
}

Expand Down
24 changes: 24 additions & 0 deletions docs/changelogs/v0.23.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Kubo changelog v0.23

- [v0.23.0](#v0230)

## v0.23.0

- [Overview](#overview)
- [🔦 Highlights](#-highlights)
- [Local Gateway: optional support for `/routing/v1` endpoint](#local-gateway-optional-support-for-routingv1-endpoint)
- [📝 Changelog](#-changelog)
- [👨‍👩‍👧‍👦 Contributors](#-contributors)

### Overview

### 🔦 Highlights

#### Local Gateway: optional support for `/routing/v1` endpoint

The local gateway, hosted at `127.0.0.1`, now supports the delegated [Routing V1](https://specs.ipfs.tech/routing/http-routing-v1/) API.
This is disabled by default, but can be enabled by setting `Config.Gateway.ExposeRoutingAPI = true`.

### 📝 Changelog

### 👨‍👩‍👧‍👦 Contributors
9 changes: 9 additions & 0 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,15 @@ Default: `true`

Type: `flag`

#### `Gateway.ExposeRoutingAPI`

An optional flag to explicitly configure whether this gateway provides a Routing
V1 endpoint. This only affects your local gateway, at `127.0.0.1`: https://specs.ipfs.tech/routing/routing-v1/.

Default: `false`

Type: `flag`

### `Gateway.HTTPHeaders`

Headers to set on gateway responses.
Expand Down
6 changes: 2 additions & 4 deletions docs/examples/kubo-as-a-library/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ go 1.18
replace github.com/ipfs/kubo => ./../../..

require (
github.com/ipfs/boxo v0.11.0
github.com/ipfs/boxo v0.11.1-0.20230808141512-7f865b36c016
github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
github.com/libp2p/go-libp2p v0.29.2
github.com/multiformats/go-multiaddr v0.10.1
Expand Down Expand Up @@ -52,7 +52,6 @@ require (
github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20230705174524-200ffdc848b8 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect
Expand Down Expand Up @@ -91,7 +90,7 @@ require (
github.com/ipfs/go-unixfsnode v1.7.1 // indirect
github.com/ipld/go-car/v2 v2.10.2-0.20230622090957-499d0c909d33 // indirect
github.com/ipld/go-codec-dagpb v1.6.0 // indirect
github.com/ipld/go-ipld-prime v0.20.0 // indirect
github.com/ipld/go-ipld-prime v0.20.1-0.20230619045951-499e9b9c2024 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect
Expand Down Expand Up @@ -153,7 +152,6 @@ require (
github.com/quic-go/quic-go v0.36.4 // indirect
github.com/quic-go/webtransport-go v0.5.3 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/samber/lo v1.36.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // indirect
Expand Down
16 changes: 6 additions & 10 deletions docs/examples/kubo-as-a-library/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJn
github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/frankban/quicktest v1.14.0/go.mod h1:NeW+ay9A/U67EYXNFA1nPE8e/tnQv/09mUdL/ijj8og=
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
Expand Down Expand Up @@ -270,7 +270,6 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
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/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
Expand Down Expand Up @@ -301,8 +300,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
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.11.0 h1:urMxhZ3xoF4HssJVD3+0ssGT9pptEfHfbL8DYdoWFlg=
github.com/ipfs/boxo v0.11.0/go.mod h1:8IfDmp+FzFGcF4zjAgHMVPpwYw4AjN9ePEzDfkaYJ1w=
github.com/ipfs/boxo v0.11.1-0.20230808141512-7f865b36c016 h1:G2W1y0vuEFE2SfJ8DOI+XY1m002tWbl77Owquj3WBQc=
github.com/ipfs/boxo v0.11.1-0.20230808141512-7f865b36c016/go.mod h1:Tbv+IR9baTM1VprtVTUMC2EPu6lR4803DahiQk5IQMk=
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY=
Expand Down Expand Up @@ -398,8 +397,8 @@ github.com/ipld/go-codec-dagpb v1.6.0 h1:9nYazfyu9B1p3NAgfVdpRco3Fs2nFC72DqVsMj6
github.com/ipld/go-codec-dagpb v1.6.0/go.mod h1:ANzFhfP2uMJxRBr8CE+WQWs5UsNa0pYtmKZ+agnUw9s=
github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8=
github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0=
github.com/ipld/go-ipld-prime v0.20.0 h1:Ud3VwE9ClxpO2LkCYP7vWPc0Fo+dYdYzgxUJZ3uRG4g=
github.com/ipld/go-ipld-prime v0.20.0/go.mod h1:PzqZ/ZR981eKbgdr3y2DJYeD/8bgMawdGVlJDE8kK+M=
github.com/ipld/go-ipld-prime v0.20.1-0.20230619045951-499e9b9c2024 h1:HfSCtpmGw0fzCfhZKzASxVjNk8tA1oSCDEF/To3eVg0=
github.com/ipld/go-ipld-prime v0.20.1-0.20230619045951-499e9b9c2024/go.mod h1:PRQpXNcJypaPiiSdarsrJABPkYrBvafwDl0B9HjujZ8=
github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd h1:gMlw/MhNr2Wtp5RwGdsW23cs+yCuj9k2ON7i9MiJlRo=
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=
Expand Down Expand Up @@ -655,8 +654,6 @@ github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjR
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/rwcarlsen/goexif v0.0.0-20190401172101-9e8deecbddbd/go.mod h1:hPqNNc0+uJM6H+SuU8sEs5K5IQeKccPqeSjfgcKGgPk=
github.com/samber/lo v1.36.0 h1:4LaOxH1mHnbDGhTVE0i1z8v/lWaQW8AIfOD3HU4mSaw=
github.com/samber/lo v1.36.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY=
github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM=
Expand Down Expand Up @@ -723,7 +720,6 @@ github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpP
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA=
github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M=
github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk=
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c h1:u6SKchux2yDvFQnDHS3lPnIRmfVJ5Sxy3ao2SIdysLQ=
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
Expand All @@ -737,7 +733,7 @@ github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMI
github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE=
github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0=
github.com/warpfork/go-testmark v0.9.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0=
github.com/warpfork/go-testmark v0.11.0 h1:J6LnV8KpceDvo7spaNU4+DauH2n1x+6RaO2rJrmpQ9U=
github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s=
github.com/warpfork/go-wish v0.0.0-20180510122957-5ad1f5abf436/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ=
Expand Down
5 changes: 2 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ require (
github.com/fsnotify/fsnotify v1.6.0
github.com/google/uuid v1.3.0
github.com/hashicorp/go-multierror v1.1.1
github.com/ipfs/boxo v0.11.0
github.com/ipfs/boxo v0.11.1-0.20230808141512-7f865b36c016
github.com/ipfs/go-block-format v0.1.2
github.com/ipfs/go-cid v0.4.1
github.com/ipfs/go-cidutil v0.1.0
Expand All @@ -39,7 +39,7 @@ require (
github.com/ipld/go-car v0.5.0
github.com/ipld/go-car/v2 v2.10.2-0.20230622090957-499d0c909d33
github.com/ipld/go-codec-dagpb v1.6.0
github.com/ipld/go-ipld-prime v0.20.0
github.com/ipld/go-ipld-prime v0.20.1-0.20230619045951-499e9b9c2024
github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c
github.com/jbenet/go-temp-err-catcher v0.1.0
github.com/jbenet/goprocess v0.1.4
Expand Down Expand Up @@ -198,7 +198,6 @@ require (
github.com/quic-go/webtransport-go v0.5.3 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/rs/cors v1.7.0 // indirect
github.com/samber/lo v1.36.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/texttheater/golang-levenshtein v0.0.0-20180516184445-d188e65d659e // indirect
github.com/tidwall/match v1.1.1 // indirect
Expand Down
Loading

0 comments on commit 0805ab6

Please sign in to comment.