@cryptotaxi247 / kubo / commits / 16479ec69

feat(provide): detailed `ipfs provide stat` (#11019)

* feat: provide stats * added N/A * format * workers stats alignment * ipfs provide stat --all --compact * consolidating compact stat * update column alignment * flags combinations errors * command description * change schedule AvgPrefixLen to float * changelog * alignments * provide stat description draft * rephrased provide-stats.md * linking provide-stats.md from command description * documentation test * fix: refactor provide stat command type handling - add extractSweepingProvider() helper to reduce nested type switching - extract lowWorkerThreshold constant for worker availability check - fix --lan error handling to work with buffered providers * docs: add clarifying comments * fix(commands): improve provide stat compact mode - prevent panic when both columns are empty - fix column alignment with UTF-8 characters - only track col0MaxWidth for first column (as intended) * test: add tests for ipfs provide stat command - test basic functionality, flags, JSON output - test legacy provider behavior - test integration with content scheduling - test disabled provider configurations - add parseSweepStats helper with t.Helper() * docs: improve provide command help text - update tagline to "Control and monitor content providing" - simplify help descriptions - make error messages more consistent - update tests to match new error messages * metrics rename ``` Next reprovide at: Next prefix: ``` updated to: ``` Next region prefix: Next region reprovide: ``` * docs: improve Provide system documentation clarity Enhance documentation for the Provide system to better explain how provider records work and the differences between sweep and legacy modes. Changes to docs/config.md: - Provide section: add clear explanation of provider records and their role - Provide.DHT: add provider record lifecycle and two provider systems overview - Provide.DHT.Interval: explain relationship to expiration, contrast sweep vs legacy behavior - Provide.DHT.SweepEnabled: rewrite to explain legacy problem, sweep solution, and efficiency gains - Monitoring section: prioritize command-line tools (ipfs provide stat) before Prometheus Changes to core/commands/provide.go: - ipfs provide stat help: add explanation of provider records, TTL expiration, and how sweep batching works Changes to docs/changelogs/v0.39.md: - Add context about why stats matter for monitoring provider health - Emphasize real-time monitoring workflow with watch command - Explain what users can observe (rates, queues, worker availability) * depend on latest kad-dht master * docs: nits --------- Co-authored-by: Marcin Rataj <lidel@lidel.org>

Guillaume Michel committed Oct 23, 2025 at 20:29 UTC 16479ec6922bcfc9e90c8042788d239b03337e78
11 files changed +1474 -252
core/commands/provide.go
+425 -37
@@ -4,33 +4,63 @@ import (
4 "errors"
5 "fmt"
6 "io"
7 + "strings"
8 "text/tabwriter"
9 "time"
10 + "unicode/utf8"
11
12 humanize "github.com/dustin/go-humanize"
11 - "github.com/ipfs/boxo/provider"
13 + boxoprovider "github.com/ipfs/boxo/provider"
14 cmds "github.com/ipfs/go-ipfs-cmds"
15 "github.com/ipfs/kubo/core/commands/cmdenv"
16 "github.com/libp2p/go-libp2p-kad-dht/fullrt"
17 + "github.com/libp2p/go-libp2p-kad-dht/provider"
18 + "github.com/libp2p/go-libp2p-kad-dht/provider/buffered"
19 + "github.com/libp2p/go-libp2p-kad-dht/provider/dual"
20 + "github.com/libp2p/go-libp2p-kad-dht/provider/stats"
21 + "github.com/probe-lab/go-libdht/kad/key"
22 "golang.org/x/exp/constraints"
23 )
24
25 const (
26 provideQuietOptionName = "quiet"
27 + provideLanOptionName = "lan"
28 +
29 + provideStatAllOptionName = "all"
30 + provideStatCompactOptionName = "compact"
31 + provideStatNetworkOptionName = "network"
32 + provideStatConnectivityOptionName = "connectivity"
33 + provideStatOperationsOptionName = "operations"
34 + provideStatTimingsOptionName = "timings"
35 + provideStatScheduleOptionName = "schedule"
36 + provideStatQueuesOptionName = "queues"
37 + provideStatWorkersOptionName = "workers"
38 +
39 + // lowWorkerThreshold is the threshold below which worker availability warnings are shown
40 + lowWorkerThreshold = 2
41 )
42
43 var ProvideCmd = &cmds.Command{
44 Status: cmds.Experimental,
45 Helptext: cmds.HelpText{
25 - Tagline: "Control providing operations",
46 + Tagline: "Control and monitor content providing",
47 ShortDescription: `
48 Control providing operations.
49
29 -NOTE: This command is experimental and not all provide-related commands have
30 -been migrated to this namespace yet. For example, 'ipfs routing
31 -provide|reprovide' are still under the routing namespace, 'ipfs stats
32 -reprovide' provides statistics. Additionally, 'ipfs bitswap reprovide' and
33 -'ipfs stats provide' are deprecated.
50 +OVERVIEW:
51 +
52 +The provider system advertises content by publishing provider records,
53 +allowing other nodes to discover which peers have specific content.
54 +Content is reprovided periodically (every Provide.DHT.Interval)
55 +according to Provide.Strategy.
56 +
57 +CONFIGURATION:
58 +
59 +Learn more: https://github.com/ipfs/kubo/blob/master/docs/config.md#provide
60 +
61 +SEE ALSO:
62 +
63 +For ad-hoc one-time provide, see 'ipfs routing provide'
64 `,
65 },
66
@@ -47,10 +77,18 @@ var provideClearCmd = &cmds.Command{
77 ShortDescription: `
78 Clear all CIDs pending to be provided for the first time.
79
50 -Note: Kubo will automatically clear the queue when it detects a change of
51 -Provide.Strategy upon a restart. For more information about provide
52 -strategies, see:
53 -https://github.com/ipfs/kubo/blob/master/docs/config.md#providestrategy
80 +BEHAVIOR:
81 +
82 +This command removes CIDs from the provide queue that are waiting to be
83 +advertised to the DHT for the first time. It does not affect content that
84 +is already being reprovided on schedule.
85 +
86 +AUTOMATIC CLEARING:
87 +
88 +Kubo will automatically clear the queue when it detects a change of
89 +Provide.Strategy upon a restart.
90 +
91 +Learn: https://github.com/ipfs/kubo/blob/master/docs/config.md#providestrategy
92 `,
93 },
94 Options: []cmds.Option{
@@ -90,25 +128,108 @@ https://github.com/ipfs/kubo/blob/master/docs/config.md#providestrategy
128 }
129
130 type provideStats struct {
93 - provider.ReproviderStats
94 - fullRT bool
131 + Sweep *stats.Stats
132 + Legacy *boxoprovider.ReproviderStats
133 + FullRT bool // only used for legacy stats
134 +}
135 +
136 +// extractSweepingProvider extracts a SweepingProvider from the given provider interface.
137 +// It handles unwrapping buffered and dual providers, selecting LAN or WAN as specified.
138 +// Returns nil if the provider is not a sweeping provider type.
139 +func extractSweepingProvider(prov any, useLAN bool) *provider.SweepingProvider {
140 + switch p := prov.(type) {
141 + case *provider.SweepingProvider:
142 + return p
143 + case *dual.SweepingProvider:
144 + if useLAN {
145 + return p.LAN
146 + }
147 + return p.WAN
148 + case *buffered.SweepingProvider:
149 + // Recursively extract from the inner provider
150 + return extractSweepingProvider(p.Provider, useLAN)
151 + default:
152 + return nil
153 + }
154 }
155
156 var provideStatCmd = &cmds.Command{
157 Status: cmds.Experimental,
158 Helptext: cmds.HelpText{
100 - Tagline: "Returns statistics about the node's provider system.",
159 + Tagline: "Show statistics about the provider system",
160 ShortDescription: `
102 -Returns statistics about the content the node is reproviding every
103 -Provide.DHT.Interval according to Provide.Strategy:
104 -https://github.com/ipfs/kubo/blob/master/docs/config.md#provide
161 +Returns statistics about the node's provider system.
162 +
163 +OVERVIEW:
164 +
165 +The provide system advertises content to the DHT by publishing provider
166 +records that map CIDs to your peer ID. These records expire after a fixed
167 +TTL to account for node churn, so content must be reprovided periodically
168 +to stay discoverable.
169 +
170 +Two provider types exist:
171 +
172 +- Sweep provider: Divides the DHT keyspace into regions and systematically
173 + sweeps through them over the reprovide interval. Batches CIDs allocated
174 + to the same DHT servers, reducing lookups from N (one per CID) to a
175 + small static number based on DHT size (~3k for 10k DHT servers). Spreads
176 + work evenly over time to prevent resource spikes and ensure announcements
177 + happen just before records expire.
178 +
179 +- Legacy provider: Processes each CID individually with separate DHT
180 + lookups. Attempts to reprovide all content as quickly as possible at the
181 + start of each cycle. Works well for small datasets but struggles with
182 + large collections.
183 +
184 +Learn more:
185 +- Config: https://github.com/ipfs/kubo/blob/master/docs/config.md#provide
186 +- Metrics: https://github.com/ipfs/kubo/blob/master/docs/provide-stats.md
187 +
188 +DEFAULT OUTPUT:
189 +
190 +Shows a brief summary including queue sizes, scheduled items, average record
191 +holders, ongoing/total provides, and worker warnings.
192 +
193 +DETAILED OUTPUT:
194 +
195 +Use --all for detailed statistics with these sections: connectivity, queues,
196 +schedule, timings, network, operations, and workers. Individual sections can
197 +be displayed with their flags (e.g., --network, --operations). Multiple flags
198 +can be combined.
199
106 -This interface is not stable and may change from release to release.
200 +Use --compact for monitoring-friendly 2-column output (requires --all).
201
202 +EXAMPLES:
203 +
204 +Monitor provider statistics in real-time with 2-column layout:
205 +
206 + watch ipfs provide stat --all --compact
207 +
208 +Get statistics in JSON format for programmatic processing:
209 +
210 + ipfs provide stat --enc=json | jq
211 +
212 +NOTES:
213 +
214 +- This interface is experimental and may change between releases
215 +- Legacy provider shows basic stats only (no flags supported)
216 +- "Regions" are keyspace divisions for spreading reprovide work
217 +- For Dual DHT: use --lan for LAN provider stats (default is WAN)
218 `,
219 },
220 Arguments: []cmds.Argument{},
111 - Options: []cmds.Option{},
221 + Options: []cmds.Option{
222 + cmds.BoolOption(provideLanOptionName, "Show stats for LAN DHT only (for Sweep+Dual DHT only)"),
223 + cmds.BoolOption(provideStatAllOptionName, "a", "Display all provide sweep stats"),
224 + cmds.BoolOption(provideStatCompactOptionName, "Display stats in 2-column layout (requires --all)"),
225 + cmds.BoolOption(provideStatConnectivityOptionName, "Display DHT connectivity status"),
226 + cmds.BoolOption(provideStatNetworkOptionName, "Display network stats (peers, reachability, region size)"),
227 + cmds.BoolOption(provideStatScheduleOptionName, "Display reprovide schedule (CIDs/regions scheduled, next reprovide time)"),
228 + cmds.BoolOption(provideStatTimingsOptionName, "Display timing information (uptime, cycle start, reprovide interval)"),
229 + cmds.BoolOption(provideStatWorkersOptionName, "Display worker pool stats (active/available/queued workers)"),
230 + cmds.BoolOption(provideStatOperationsOptionName, "Display operation stats (ongoing/past provides, rates, errors)"),
231 + cmds.BoolOption(provideStatQueuesOptionName, "Display provide and reprovide queue sizes"),
232 + },
233 Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
234 nd, err := cmdenv.GetNode(env)
235 if err != nil {
@@ -119,35 +240,271 @@ This interface is not stable and may change from release to release.
240 return ErrNotOnline
241 }
242
122 - provideSys, ok := nd.Provider.(provider.System)
123 - if !ok {
124 - return errors.New("stats not available with experimental sweeping provider (Provide.DHT.SweepEnabled=true)")
125 - }
243 + lanStats, _ := req.Options[provideLanOptionName].(bool)
244
127 - stats, err := provideSys.Stat()
128 - if err != nil {
129 - return err
245 + // Handle legacy provider
246 + if legacySys, ok := nd.Provider.(boxoprovider.System); ok {
247 + if lanStats {
248 + return errors.New("LAN stats only available for Sweep provider with Dual DHT")
249 + }
250 + stats, err := legacySys.Stat()
251 + if err != nil {
252 + return err
253 + }
254 + _, fullRT := nd.DHTClient.(*fullrt.FullRT)
255 + return res.Emit(provideStats{Legacy: &stats, FullRT: fullRT})
256 }
131 - _, fullRT := nd.DHTClient.(*fullrt.FullRT)
257
133 - if err := res.Emit(provideStats{stats, fullRT}); err != nil {
134 - return err
258 + // Extract sweeping provider (handles buffered and dual unwrapping)
259 + sweepingProvider := extractSweepingProvider(nd.Provider, lanStats)
260 + if sweepingProvider == nil {
261 + if lanStats {
262 + return errors.New("LAN stats only available for Sweep provider with Dual DHT")
263 + }
264 + return fmt.Errorf("stats not available with current routing system %T", nd.Provider)
265 }
266
137 - return nil
267 + s := sweepingProvider.Stats()
268 + return res.Emit(provideStats{Sweep: &s})
269 },
270 Encoders: cmds.EncoderMap{
271 cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, s provideStats) error {
272 wtr := tabwriter.NewWriter(w, 1, 2, 1, ' ', 0)
273 defer wtr.Flush()
274
144 - fmt.Fprintf(wtr, "TotalReprovides:\t%s\n", humanNumber(s.TotalReprovides))
145 - fmt.Fprintf(wtr, "AvgReprovideDuration:\t%s\n", humanDuration(s.AvgReprovideDuration))
146 - fmt.Fprintf(wtr, "LastReprovideDuration:\t%s\n", humanDuration(s.LastReprovideDuration))
147 - if !s.LastRun.IsZero() {
148 - fmt.Fprintf(wtr, "LastReprovide:\t%s\n", humanTime(s.LastRun))
149 - if s.fullRT {
150 - fmt.Fprintf(wtr, "NextReprovide:\t%s\n", humanTime(s.LastRun.Add(s.ReprovideInterval)))
275 + all, _ := req.Options[provideStatAllOptionName].(bool)
276 + compact, _ := req.Options[provideStatCompactOptionName].(bool)
277 + connectivity, _ := req.Options[provideStatConnectivityOptionName].(bool)
278 + queues, _ := req.Options[provideStatQueuesOptionName].(bool)
279 + schedule, _ := req.Options[provideStatScheduleOptionName].(bool)
280 + network, _ := req.Options[provideStatNetworkOptionName].(bool)
281 + timings, _ := req.Options[provideStatTimingsOptionName].(bool)
282 + operations, _ := req.Options[provideStatOperationsOptionName].(bool)
283 + workers, _ := req.Options[provideStatWorkersOptionName].(bool)
284 +
285 + flagCount := 0
286 + for _, enabled := range []bool{all, connectivity, queues, schedule, network, timings, operations, workers} {
287 + if enabled {
288 + flagCount++
289 + }
290 + }
291 +
292 + if s.Legacy != nil {
293 + if flagCount > 0 {
294 + return errors.New("cannot use flags with legacy provide stats")
295 + }
296 + fmt.Fprintf(wtr, "TotalReprovides:\t%s\n", humanNumber(s.Legacy.TotalReprovides))
297 + fmt.Fprintf(wtr, "AvgReprovideDuration:\t%s\n", humanDuration(s.Legacy.AvgReprovideDuration))
298 + fmt.Fprintf(wtr, "LastReprovideDuration:\t%s\n", humanDuration(s.Legacy.LastReprovideDuration))
299 + if !s.Legacy.LastRun.IsZero() {
300 + fmt.Fprintf(wtr, "LastReprovide:\t%s\n", humanTime(s.Legacy.LastRun))
301 + if s.FullRT {
302 + fmt.Fprintf(wtr, "NextReprovide:\t%s\n", humanTime(s.Legacy.LastRun.Add(s.Legacy.ReprovideInterval)))
303 + }
304 + }
305 + return nil
306 + }
307 +
308 + if s.Sweep == nil {
309 + return errors.New("no provide stats available")
310 + }
311 +
312 + // Sweep provider stats
313 + if s.Sweep.Closed {
314 + fmt.Fprintf(wtr, "Provider is closed\n")
315 + return nil
316 + }
317 +
318 + if compact && !all {
319 + return errors.New("--compact requires --all flag")
320 + }
321 +
322 + brief := flagCount == 0
323 + showHeadings := flagCount > 1 || all
324 +
325 + compactMode := all && compact
326 + var cols [2][]string
327 + col0MaxWidth := 0
328 + // formatLine handles both normal and compact output modes:
329 + // - Normal mode: all lines go to cols[0], col parameter is ignored
330 + // - Compact mode: col 0 for left column, col 1 for right column
331 + formatLine := func(col int, format string, a ...any) {
332 + if compactMode {
333 + s := fmt.Sprintf(format, a...)
334 + cols[col] = append(cols[col], s)
335 + if col == 0 {
336 + col0MaxWidth = max(col0MaxWidth, utf8.RuneCountInString(s))
337 + }
338 + return
339 + }
340 + format = strings.Replace(format, ": ", ":\t", 1)
341 + format = strings.Replace(format, ", ", ",\t", 1)
342 + cols[0] = append(cols[0], fmt.Sprintf(format, a...))
343 + }
344 + addBlankLine := func(col int) {
345 + if !brief {
346 + formatLine(col, "")
347 + }
348 + }
349 + sectionTitle := func(col int, title string) {
350 + if !brief && showHeadings {
351 + formatLine(col, title+":")
352 + }
353 + }
354 +
355 + indent := " "
356 + if brief || !showHeadings {
357 + indent = ""
358 + }
359 +
360 + // Connectivity
361 + if all || connectivity || brief && s.Sweep.Connectivity.Status != "online" {
362 + sectionTitle(1, "Connectivity")
363 + since := s.Sweep.Connectivity.Since
364 + if since.IsZero() {
365 + formatLine(1, "%sStatus: %s", indent, s.Sweep.Connectivity.Status)
366 + } else {
367 + formatLine(1, "%sStatus: %s (%s)", indent, s.Sweep.Connectivity.Status, humanTime(since))
368 + }
369 + addBlankLine(1)
370 + }
371 +
372 + // Queues
373 + if all || queues || brief {
374 + sectionTitle(1, "Queues")
375 + formatLine(1, "%sProvide queue: %s CIDs, %s regions", indent, humanNumber(s.Sweep.Queues.PendingKeyProvides), humanNumber(s.Sweep.Queues.PendingRegionProvides))
376 + formatLine(1, "%sReprovide queue: %s regions", indent, humanNumber(s.Sweep.Queues.PendingRegionReprovides))
377 + addBlankLine(1)
378 + }
379 +
380 + // Schedule
381 + if all || schedule || brief {
382 + sectionTitle(0, "Schedule")
383 + formatLine(0, "%sCIDs scheduled: %s", indent, humanNumber(s.Sweep.Schedule.Keys))
384 + formatLine(0, "%sRegions scheduled: %s", indent, humanNumberOrNA(s.Sweep.Schedule.Regions))
385 + if !brief {
386 + formatLine(0, "%sAvg prefix length: %s", indent, humanFloatOrNA(s.Sweep.Schedule.AvgPrefixLength))
387 + nextPrefix := key.BitString(s.Sweep.Schedule.NextReprovidePrefix)
388 + if nextPrefix == "" {
389 + nextPrefix = "N/A"
390 + }
391 + formatLine(0, "%sNext region prefix: %s", indent, nextPrefix)
392 + nextReprovideAt := s.Sweep.Schedule.NextReprovideAt.Format("15:04:05")
393 + if s.Sweep.Schedule.NextReprovideAt.IsZero() {
394 + nextReprovideAt = "N/A"
395 + }
396 + formatLine(0, "%sNext region reprovide: %s", indent, nextReprovideAt)
397 + }
398 + addBlankLine(0)
399 + }
400 +
401 + // Timings
402 + if all || timings {
403 + sectionTitle(1, "Timings")
404 + formatLine(1, "%sUptime: %s (%s)", indent, humanDuration(s.Sweep.Timing.Uptime), humanTime(time.Now().Add(-s.Sweep.Timing.Uptime)))
405 + formatLine(1, "%sCurrent time offset: %s", indent, humanDuration(s.Sweep.Timing.CurrentTimeOffset))
406 + formatLine(1, "%sCycle started: %s", indent, humanTime(s.Sweep.Timing.CycleStart))
407 + formatLine(1, "%sReprovide interval: %s", indent, humanDuration(s.Sweep.Timing.ReprovidesInterval))
408 + addBlankLine(1)
409 + }
410 +
411 + // Network
412 + if all || network || brief {
413 + sectionTitle(0, "Network")
414 + formatLine(0, "%sAvg record holders: %s", indent, humanFloatOrNA(s.Sweep.Network.AvgHolders))
415 + if !brief {
416 + formatLine(0, "%sPeers swept: %s", indent, humanNumber(s.Sweep.Network.Peers))
417 + formatLine(0, "%sFull keyspace coverage: %t", indent, s.Sweep.Network.CompleteKeyspaceCoverage)
418 + if s.Sweep.Network.Peers > 0 {
419 + formatLine(0, "%sReachable peers: %s (%s%%)", indent, humanNumber(s.Sweep.Network.Reachable), humanNumber(100*s.Sweep.Network.Reachable/s.Sweep.Network.Peers))
420 + } else {
421 + formatLine(0, "%sReachable peers: %s", indent, humanNumber(s.Sweep.Network.Reachable))
422 + }
423 + formatLine(0, "%sAvg region size: %s", indent, humanFloatOrNA(s.Sweep.Network.AvgRegionSize))
424 + formatLine(0, "%sReplication factor: %s", indent, humanNumber(s.Sweep.Network.ReplicationFactor))
425 + addBlankLine(0)
426 + }
427 + }
428 +
429 + // Operations
430 + if all || operations || brief {
431 + sectionTitle(1, "Operations")
432 + // Ongoing operations
433 + formatLine(1, "%sOngoing provides: %s CIDs, %s regions", indent, humanNumber(s.Sweep.Operations.Ongoing.KeyProvides), humanNumber(s.Sweep.Operations.Ongoing.RegionProvides))
434 + formatLine(1, "%sOngoing reprovides: %s CIDs, %s regions", indent, humanNumber(s.Sweep.Operations.Ongoing.KeyReprovides), humanNumber(s.Sweep.Operations.Ongoing.RegionReprovides))
435 + // Past operations summary
436 + formatLine(1, "%sTotal CIDs provided: %s", indent, humanNumber(s.Sweep.Operations.Past.KeysProvided))
437 + if !brief {
438 + formatLine(1, "%sTotal records provided: %s", indent, humanNumber(s.Sweep.Operations.Past.RecordsProvided))
439 + formatLine(1, "%sTotal provide errors: %s", indent, humanNumber(s.Sweep.Operations.Past.KeysFailed))
440 + formatLine(1, "%sCIDs provided/min: %s", indent, humanFloatOrNA(s.Sweep.Operations.Past.KeysProvidedPerMinute))
441 + formatLine(1, "%sCIDs reprovided/min: %s", indent, humanFloatOrNA(s.Sweep.Operations.Past.KeysReprovidedPerMinute))
442 + formatLine(1, "%sRegion reprovide duration: %s", indent, humanDurationOrNA(s.Sweep.Operations.Past.RegionReprovideDuration))
443 + formatLine(1, "%sAvg CIDs/reprovide: %s", indent, humanFloatOrNA(s.Sweep.Operations.Past.AvgKeysPerReprovide))
444 + formatLine(1, "%sRegions reprovided (last cycle): %s", indent, humanNumber(s.Sweep.Operations.Past.RegionReprovidedLastCycle))
445 + addBlankLine(1)
446 + }
447 + }
448 +
449 + // Workers
450 + displayWorkers := all || workers
451 + if displayWorkers || brief {
452 + availableReservedBurst := max(0, s.Sweep.Workers.DedicatedBurst-s.Sweep.Workers.ActiveBurst)
453 + availableReservedPeriodic := max(0, s.Sweep.Workers.DedicatedPeriodic-s.Sweep.Workers.ActivePeriodic)
454 + availableFreeWorkers := s.Sweep.Workers.Max - max(s.Sweep.Workers.DedicatedBurst, s.Sweep.Workers.ActiveBurst) - max(s.Sweep.Workers.DedicatedPeriodic, s.Sweep.Workers.ActivePeriodic)
455 + availableBurst := availableFreeWorkers + availableReservedBurst
456 + availablePeriodic := availableFreeWorkers + availableReservedPeriodic
457 +
458 + if displayWorkers || availableBurst <= lowWorkerThreshold || availablePeriodic <= lowWorkerThreshold {
459 + // Either we want to display workers information, or we are low on
460 + // available workers and want to warn the user.
461 + sectionTitle(0, "Workers")
462 + specifyWorkers := " workers"
463 + if compactMode {
464 + specifyWorkers = ""
465 + }
466 + formatLine(0, "%sActive%s: %s / %s (max)", indent, specifyWorkers, humanNumber(s.Sweep.Workers.Active), humanNumber(s.Sweep.Workers.Max))
467 + if brief {
468 + // Brief mode - show condensed worker info
469 + formatLine(0, "%sPeriodic%s: %s active, %s available, %s queued", indent, specifyWorkers,
470 + humanNumber(s.Sweep.Workers.ActivePeriodic), humanNumber(availablePeriodic), humanNumber(s.Sweep.Workers.QueuedPeriodic))
471 + formatLine(0, "%sBurst%s: %s active, %s available, %s queued\n", indent, specifyWorkers,
472 + humanNumber(s.Sweep.Workers.ActiveBurst), humanNumber(availableBurst), humanNumber(s.Sweep.Workers.QueuedBurst))
473 + } else {
474 + formatLine(0, "%sFree%s: %s", indent, specifyWorkers, humanNumber(availableFreeWorkers))
475 + formatLine(0, "%sWorkers stats:%s %-9s %s", indent, " ", "Periodic", "Burst")
476 + formatLine(0, "%s %-14s %-9s %s", indent, "Active:", humanNumber(s.Sweep.Workers.ActivePeriodic), humanNumber(s.Sweep.Workers.ActiveBurst))
477 + formatLine(0, "%s %-14s %-9s %s", indent, "Dedicated:", humanNumber(s.Sweep.Workers.DedicatedPeriodic), humanNumber(s.Sweep.Workers.DedicatedBurst))
478 + formatLine(0, "%s %-14s %-9s %s", indent, "Available:", humanNumber(availablePeriodic), humanNumber(availableBurst))
479 + formatLine(0, "%s %-14s %-9s %s", indent, "Queued:", humanNumber(s.Sweep.Workers.QueuedPeriodic), humanNumber(s.Sweep.Workers.QueuedBurst))
480 + formatLine(0, "%sMax connections/worker: %s", indent, humanNumber(s.Sweep.Workers.MaxProvideConnsPerWorker))
481 + addBlankLine(0)
482 + }
483 + }
484 + }
485 + if compactMode {
486 + col0Width := col0MaxWidth + 2
487 + // Print both columns side by side
488 + maxRows := max(len(cols[0]), len(cols[1]))
489 + if maxRows == 0 {
490 + return nil
491 + }
492 + for i := range maxRows - 1 { // last line is empty
493 + var left, right string
494 + if i < len(cols[0]) {
495 + left = cols[0][i]
496 + }
497 + if i < len(cols[1]) {
498 + right = cols[1][i]
499 + }
500 + fmt.Fprintf(wtr, "%-*s %s\n", col0Width, left, right)
501 + }
502 + } else {
503 + if !brief {
504 + cols[0] = cols[0][:len(cols[0])-1] // remove last blank line
505 + }
506 + for _, line := range cols[0] {
507 + fmt.Fprintln(wtr, line)
508 }
509 }
510 return nil
@@ -157,10 +514,23 @@ This interface is not stable and may change from release to release.
514 }
515
516 func humanDuration(val time.Duration) string {
517 + if val > time.Second {
518 + return val.Truncate(100 * time.Millisecond).String()
519 + }
520 return val.Truncate(time.Microsecond).String()
521 }
522
523 +func humanDurationOrNA(val time.Duration) string {
524 + if val <= 0 {
525 + return "N/A"
526 + }
527 + return humanDuration(val)
528 +}
529 +
530 func humanTime(val time.Time) string {
531 + if val.IsZero() {
532 + return "N/A"
533 + }
534 return val.Format("2006-01-02 15:04:05")
535 }
536
@@ -174,6 +544,24 @@ func humanNumber[T constraints.Float | constraints.Integer](n T) string {
544 return str
545 }
546
547 +// humanNumberOrNA is like humanNumber but returns "N/A" for non-positive values.
548 +func humanNumberOrNA[T constraints.Float | constraints.Integer](n T) string {
549 + if n <= 0 {
550 + return "N/A"
551 + }
552 + return humanNumber(n)
553 +}
554 +
555 +// humanFloatOrNA formats a float with 1 decimal place, returning "N/A" for non-positive values.
556 +// This is separate from humanNumberOrNA because it provides simple decimal formatting for
557 +// continuous metrics (averages, rates) rather than SI unit formatting used for discrete counts.
558 +func humanFloatOrNA(val float64) string {
559 + if val <= 0 {
560 + return "N/A"
561 + }
562 + return fmt.Sprintf("%.1f", val)
563 +}
564 +
565 func humanSI(val float64, decimals int) string {
566 v, unit := humanize.ComputeSI(val)
567 return fmt.Sprintf("%s%s", humanFull(v, decimals), unit)
docs/changelogs/v0.39.md
+45 -1
@@ -10,6 +10,8 @@ This release was brought to you by the [Shipyard](https://ipshipyard.com/) team.
10
11 - [Overview](#overview)
12 - [🔦 Highlights](#-highlights)
13 + - [📊 Detailed statistics for Sweep provider with `ipfs provide stat`](#-detailed-statistics-for-sweep-provider-with-ipfs-provide-stat)
14 + - [🪦 Deprecated `go-ipfs` name no longer published](#-deprecated-go-ipfs-name-no-longer-published)
15 - [📦️ Important dependency updates](#-important-dependency-updates)
16 - [📝 Changelog](#-changelog)
17 - [👨‍👩‍👧‍👦 Contributors](#-contributors)
@@ -18,13 +20,55 @@ This release was brought to you by the [Shipyard](https://ipshipyard.com/) team.
20
21 ### 🔦 Highlights
22
23 +#### 📊 Detailed statistics for Sweep provider with `ipfs provide stat`
24 +
25 +The experimental Sweep provider system ([introduced in
26 +v0.38](https://github.com/ipfs/kubo/blob/master/docs/changelogs/v0.38.md#-experimental-sweeping-dht-provider))
27 +now has detailed statistics available through `ipfs provide stat`.
28 +
29 +These statistics help you monitor provider health and troubleshoot issues,
30 +especially useful for nodes providing large content collections. You can quickly
31 +identify bottlenecks like queue backlog, worker saturation, or connectivity
32 +problems that might prevent content from being announced to the DHT.
33 +
34 +**Default behavior:** Displays a brief summary showing queue sizes, scheduled
35 +CIDs/regions, average record holders, ongoing/total provides, and worker status
36 +when resources are constrained.
37 +
38 +**Detailed statistics with `--all`:** View complete metrics organized into sections:
39 +
40 +- **Connectivity**: DHT connection status
41 +- **Queues**: Pending provide and reprovide operations
42 +- **Schedule**: CIDs/regions scheduled for reprovide
43 +- **Timings**: Uptime, reprovide cycle information
44 +- **Network**: Peer statistics, keyspace region sizes
45 +- **Operations**: Ongoing and past provides, rates, errors
46 +- **Workers**: Worker pool utilization and availability
47 +
48 +**Real-time monitoring:** For continuous monitoring, run
49 +`watch ipfs provide stat --all --compact` to see detailed statistics refreshed
50 +in a 2-column layout. This lets you observe provide rates, queue sizes, and
51 +worker availability in real-time. Individual sections can be displayed using
52 +flags like `--network`, `--operations`, or `--workers`, and multiple flags can
53 +be combined for custom views.
54 +
55 +**Dual DHT support:** For Dual DHT configurations, use `--lan` to view LAN DHT
56 +provider statistics instead of the default WAN DHT stats.
57 +
58 +> [!NOTE]
59 +> These statistics are only available when using the Sweep provider system
60 +> (enabled via
61 +> [`Provide.DHT.SweepEnabled`](https://github.com/ipfs/kubo/blob/master/docs/config.md#providedhtsweepenabled)).
62 +> Legacy provider shows basic statistics without flag support.
63 +
64 #### 🪦 Deprecated `go-ipfs` name no longer published
65
66 The `go-ipfs` name was deprecated in 2022 and renamed to `kubo`. Starting with this release, we have stopped publishing Docker images and distribution binaries under the old `go-ipfs` name.
67
68 Existing users should switch to:
69 +
70 - Docker: `ipfs/kubo` image (instead of `ipfs/go-ipfs`)
27 -- Binaries: download from https://dist.ipfs.tech/kubo/ or https://github.com/ipfs/kubo/releases
71 +- Binaries: download from <https://dist.ipfs.tech/kubo/> or <https://github.com/ipfs/kubo/releases>
72
73 For Docker users, the legacy `ipfs/go-ipfs` image name now shows a deprecation notice directing you to `ipfs/kubo`.
74
docs/config.md
+102 -43
@@ -1910,10 +1910,17 @@ Type: `duration`
1910
1911 ## `Provide`
1912
1913 -Configures CID announcements to the routing system, including both immediate
1914 -announcements for new content (provide) and periodic re-announcements
1915 -(reprovide) on systems that require it, like Amino DHT. While designed to support
1916 -multiple routing systems in the future, the current default configuration only supports providing to the Amino DHT.
1913 +Configures how your node advertises content to make it discoverable by other
1914 +peers.
1915 +
1916 +**What is providing?** When your node stores content, it publishes provider
1917 +records to the routing system announcing "I have this content". These records
1918 +map CIDs to your peer ID, enabling content discovery across the network.
1919 +
1920 +While designed to support multiple routing systems in the future, the current
1921 +default configuration only supports [providing to the Amino DHT](#providedht).
1922 +
1923 +<!-- TODO: See the [Reprovide Sweep blog post](https://blog.ipfs.tech/2025-reprovide-sweep/) for detailed performance comparisons. -->
1924
1925 ### `Provide.Enabled`
1926
@@ -1964,13 +1971,39 @@ Type: `optionalString` (unset for the default)
1971
1972 Configuration for providing data to Amino DHT peers.
1973
1974 +**Provider record lifecycle:** On the Amino DHT, provider records expire after
1975 +[`amino.DefaultProvideValidity`](https://github.com/libp2p/go-libp2p-kad-dht/blob/v0.34.0/amino/defaults.go#L40-L43).
1976 +Your node must re-announce (reprovide) content periodically to keep it
1977 +discoverable. The [`Provide.DHT.Interval`](#providedhtinterval) setting
1978 +controls this timing, with the default ensuring records refresh well before
1979 +expiration or negative churn effects kick in.
1980 +
1981 +**Two provider systems:**
1982 +
1983 +- **Sweep provider**: Divides the DHT keyspace into regions and systematically
1984 + sweeps through them over the reprovide interval. This batches CIDs allocated
1985 + to the same DHT servers, dramatically reducing the number of DHT lookups and
1986 + PUTs needed. Spreads work evenly over time with predictable resource usage.
1987 +
1988 +- **Legacy provider**: Processes each CID individually with separate DHT
1989 + lookups. Works well for small content collections but struggles to complete
1990 + reprovide cycles when managing thousands of CIDs.
1991 +
1992 #### Monitoring Provide Operations
1993
1969 -You can monitor the effectiveness of your provide configuration through metrics exposed at the Prometheus endpoint: `{Addresses.API}/debug/metrics/prometheus` (default: `http://127.0.0.1:5001/debug/metrics/prometheus`).
1994 +**Quick command-line monitoring:** Use `ipfs provide stat` to view the current
1995 +state of the provider system. For real-time monitoring, run
1996 +`watch ipfs provide stat --all --compact` to see detailed statistics refreshed
1997 +continuously in a 2-column layout.
1998
1971 -Different metrics are available depending on whether you use legacy mode (`SweepEnabled=false`) or sweep mode (`SweepEnabled=true`). See [Provide metrics documentation](https://github.com/ipfs/kubo/blob/master/docs/metrics.md#provide) for details.
1999 +**Long-term monitoring:** For in-depth or long-term monitoring, metrics are
2000 +exposed at the Prometheus endpoint: `{Addresses.API}/debug/metrics/prometheus`
2001 +(default: `http://127.0.0.1:5001/debug/metrics/prometheus`). Different metrics
2002 +are available depending on whether you use legacy mode (`SweepEnabled=false`) or
2003 +sweep mode (`SweepEnabled=true`). See [Provide metrics documentation](https://github.com/ipfs/kubo/blob/master/docs/metrics.md#provide)
2004 +for details.
2005
1973 -To enable detailed debug logging for both providers, set:
2006 +**Debug logging:** For troubleshooting, enable detailed logging by setting:
2007
2008 ```sh
2009 GOLOG_LOG_LEVEL=error,provider=debug,dht/provider=debug
@@ -1982,12 +2015,24 @@ GOLOG_LOG_LEVEL=error,provider=debug,dht/provider=debug
2015 #### `Provide.DHT.Interval`
2016
2017 Sets how often to re-announce content to the DHT. Provider records on Amino DHT
1985 -expire after [`amino.DefaultProvideValidity`](https://github.com/libp2p/go-libp2p-kad-dht/blob/v0.34.0/amino/defaults.go#L40-L43),
1986 -also known as Provider Record Expiration Interval.
2018 +expire after [`amino.DefaultProvideValidity`](https://github.com/libp2p/go-libp2p-kad-dht/blob/v0.34.0/amino/defaults.go#L40-L43).
2019 +
2020 +**Why this matters:** The interval must be shorter than the expiration window to
2021 +ensure provider records refresh before they expire. The default value is
2022 +approximately half of [`amino.DefaultProvideValidity`](https://github.com/libp2p/go-libp2p-kad-dht/blob/v0.34.0/amino/defaults.go#L40-L43),
2023 +which accounts for network churn and ensures records stay alive without
2024 +overwhelming the network with unnecessary announcements.
2025
1988 -An interval of about half the expiration window ensures provider records
1989 -are refreshed well before they expire. This keeps your content continuously
1990 -discoverable accounting for network churn without overwhelming the network with too frequent announcements.
2026 +**With sweep mode enabled
2027 +([`Provide.DHT.SweepEnabled`](#providedhtsweepenabled)):** The system spreads
2028 +reprovide operations smoothly across this entire interval. Each keyspace region
2029 +is reprovided at scheduled times throughout the period, ensuring announcements
2030 +periodically happen every interval.
2031 +
2032 +**With legacy mode:** The system attempts to reprovide all CIDs as quickly as
2033 +possible at the start of each interval. If reproviding takes longer than this
2034 +interval (common with large datasets), the next cycle is skipped and provider
2035 +records may expire.
2036
2037 - If unset, it uses the implicit safe default.
2038 - If set to the value `"0"` it will disable content reproviding to DHT.
@@ -2055,32 +2100,44 @@ Type: `optionalInteger` (non-negative; `0` means unlimited number of workers)
2100
2101 #### `Provide.DHT.SweepEnabled`
2102
2058 -Whether Provide Sweep is enabled. If not enabled, the legacy
2059 -[`boxo/provider`](https://github.com/ipfs/boxo/tree/main/provider) is used for
2060 -both provides and reprovides.
2061 -
2062 -Provide Sweep is a resource efficient technique for advertising content to
2063 -the Amino DHT swarm. The Provide Sweep module tracks the keys that should be periodically reprovided in
2064 -the `Keystore`. It splits the keys into DHT keyspace regions by proximity (XOR
2065 -distance), and schedules when reprovides should happen in order to spread the
2066 -reprovide operation over time to avoid a spike in resource utilization. It
2067 -basically sweeps the keyspace _from left to right_ over the
2068 -[`Provide.DHT.Interval`](#providedhtinterval) time period, and reprovides keys
2069 -matching to the visited keyspace region.
2070 -
2071 -Provide Sweep aims at replacing the inefficient legacy `boxo/provider`
2072 -module, and is currently opt-in. You can compare the effectiveness of sweep mode vs legacy mode by monitoring the appropriate metrics (see [Monitoring Provide Operations](#monitoring-provide-operations) above).
2073 -
2074 -Whenever new keys should be advertised to the Amino DHT, `kubo` calls
2075 -`StartProviding()`, triggering an initial `provide` operation for the given
2076 -keys. The keys will be added to the `Keystore` tracking which keys should be
2077 -reprovided and when they should be reprovided. Calling `StopProviding()`
2078 -removes the keys from the `Keystore`. However, it is currently tricky for
2079 -`kubo` to detect when a key should stop being advertised. Hence, `kubo` will
2080 -periodically refresh the `Keystore` at each [`Provide.DHT.Interval`](#providedhtinterval)
2081 -by providing it a channel of all the keys it is expected to contain according
2082 -to the [`Provide.Strategy`](#providestrategy). During this operation,
2083 -all keys in the `Keystore` are purged, and only the given ones remain scheduled.
2103 +Enables the sweep provider for efficient content announcements. When disabled,
2104 +the legacy [`boxo/provider`](https://github.com/ipfs/boxo/tree/main/provider) is
2105 +used instead.
2106 +
2107 +**The legacy provider problem:** The legacy system processes CIDs one at a
2108 +time, requiring a separate DHT lookup (10-20 seconds each) to find the 20
2109 +closest peers for each CID. This sequential approach typically handles less
2110 +than 10,000 CID over 22h ([`Provide.DHT.Interval`](#providedhtinterval)). If
2111 +your node has more CIDs than can be reprovided within
2112 +[`Provide.DHT.Interval`](#providedhtinterval), provider records start expiring
2113 +after
2114 +[`amino.DefaultProvideValidity`](https://github.com/libp2p/go-libp2p-kad-dht/blob/v0.34.0/amino/defaults.go#L40-L43),
2115 +making content undiscoverable.
2116 +
2117 +**How sweep mode works:** The sweep provider divides the DHT keyspace into
2118 +regions based on keyspace prefixes. It estimates the Amino DHT size, calculates
2119 +how many regions are needed (sized to contain at least 20 peers each), then
2120 +schedules region processing evenly across
2121 +[`Provide.DHT.Interval`](#providedhtinterval). When processing a region, it
2122 +discovers the peers in that region once, then sends all provider records for
2123 +CIDs allocated to those peers in a batch. This batching is the key efficiency:
2124 +instead of N lookups for N CIDs, the number of lookups is bounded by a constant
2125 +fraction of the Amino DHT size (e.g., ~3,000 lookups when there are ~10,000 DHT
2126 +servers), regardless of how many CIDs you're providing.
2127 +
2128 +**Efficiency gains:** For a node providing 100,000 CIDs, sweep mode reduces
2129 +lookups by 97% compared to legacy. The work spreads smoothly over time rather
2130 +than completing in bursts, preventing resource spikes and duplicate
2131 +announcements. Long-running nodes reprovide systematically just before records
2132 +would expire, keeping content continuously discoverable without wasting
2133 +bandwidth.
2134 +
2135 +**Implementation details:** The sweep provider tracks CIDs in a persistent
2136 +keystore. New content added via `StartProviding()` enters the provide queue and
2137 +gets batched by keyspace region. The keystore is periodically refreshed at each
2138 +[`Provide.DHT.Interval`](#providedhtinterval) with CIDs matching
2139 +[`Provide.Strategy`](#providestrategy) to ensure only current content remains
2140 +scheduled. This handles cases where content is unpinned or removed.
2141
2142 > <picture>
2143 > <source media="(prefers-color-scheme: dark)" srcset="https://github.com/user-attachments/assets/f6e06b08-7fee-490c-a681-1bf440e16e27">
@@ -2088,13 +2145,15 @@ all keys in the `Keystore` are purged, and only the given ones remain scheduled.
2145 > <img alt="Reprovide Cycle Comparison" src="https://github.com/user-attachments/assets/e1662d7c-f1be-4275-a9ed-f2752fcdcabe">
2146 > </picture>
2147 >
2091 -> The diagram above visualizes the performance patterns:
2148 +> The diagram compares performance patterns:
2149 >
2093 -> - **Legacy mode**: Individual (slow) provides per CID, can struggle with large datasets
2094 -> - **Sweep mode**: Even distribution matching the keyspace sweep described with low resource usage
2095 -> - **Accelerated DHT**: Hourly traffic spikes with high resource usage
2150 +> - **Legacy mode**: Sequential processing, one lookup per CID, struggles with large datasets
2151 +> - **Sweep mode**: Smooth distribution over time, batched lookups by keyspace region, predictable resource usage
2152 +> - **Accelerated DHT**: Hourly network crawls creating traffic spikes, high resource usage
2153 >
2097 -> Sweep mode provides similar effectiveness to Accelerated DHT but with steady resource usage - better for machines with limited CPU, memory, or network bandwidth.
2154 +> Sweep mode achieves similar effectiveness to the Accelerated DHT client but with steady resource consumption.
2155 +
2156 +You can compare the effectiveness of sweep mode vs legacy mode by monitoring the appropriate metrics (see [Monitoring Provide Operations](#monitoring-provide-operations) above).
2157
2158 > [!NOTE]
2159 > This feature is opt-in for now, but will become the default in a future release.
docs/examples/kubo-as-a-library/go.mod
+17 -17
@@ -7,9 +7,9 @@ go 1.25
7 replace github.com/ipfs/kubo => ./../../..
8
9 require (
10 - github.com/ipfs/boxo v0.35.1-0.20251016232905-37006871a40e
10 + github.com/ipfs/boxo v0.35.0
11 github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
12 - github.com/libp2p/go-libp2p v0.44.0
12 + github.com/libp2p/go-libp2p v0.43.0
13 github.com/multiformats/go-multiaddr v0.16.1
14 )
15
@@ -82,7 +82,7 @@ require (
82 github.com/ipfs/go-ds-flatfs v0.5.5 // indirect
83 github.com/ipfs/go-ds-leveldb v0.5.2 // indirect
84 github.com/ipfs/go-ds-measure v0.2.2 // indirect
85 - github.com/ipfs/go-ds-pebble v0.5.5 // indirect
85 + github.com/ipfs/go-ds-pebble v0.5.3 // indirect
86 github.com/ipfs/go-dsqueue v0.1.0 // indirect
87 github.com/ipfs/go-fs-lock v0.1.1 // indirect
88 github.com/ipfs/go-ipfs-cmds v0.15.0 // indirect
@@ -98,7 +98,7 @@ require (
98 github.com/ipfs/go-peertaskqueue v0.8.2 // indirect
99 github.com/ipfs/go-test v0.2.3 // indirect
100 github.com/ipfs/go-unixfsnode v1.10.2 // indirect
101 - github.com/ipld/go-car/v2 v2.16.0 // indirect
101 + github.com/ipld/go-car/v2 v2.15.0 // indirect
102 github.com/ipld/go-codec-dagpb v1.7.0 // indirect
103 github.com/ipld/go-ipld-prime v0.21.0 // indirect
104 github.com/ipshipyard/p2p-forge v0.6.1 // indirect
@@ -115,7 +115,7 @@ require (
115 github.com/libp2p/go-doh-resolver v0.5.0 // indirect
116 github.com/libp2p/go-flow-metrics v0.3.0 // indirect
117 github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
118 - github.com/libp2p/go-libp2p-kad-dht v0.35.1 // indirect
118 + github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251017193437-abd04263daac // indirect
119 github.com/libp2p/go-libp2p-kbucket v0.8.0 // indirect
120 github.com/libp2p/go-libp2p-pubsub v0.14.2 // indirect
121 github.com/libp2p/go-libp2p-pubsub-router v0.6.0 // indirect
@@ -123,7 +123,7 @@ require (
123 github.com/libp2p/go-libp2p-routing-helpers v0.7.5 // indirect
124 github.com/libp2p/go-libp2p-xor v0.1.0 // indirect
125 github.com/libp2p/go-msgio v0.3.0 // indirect
126 - github.com/libp2p/go-netroute v0.3.0 // indirect
126 + github.com/libp2p/go-netroute v0.2.2 // indirect
127 github.com/libp2p/go-reuseport v0.4.0 // indirect
128 github.com/libp2p/go-yamux/v5 v5.0.1 // indirect
129 github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
@@ -141,7 +141,7 @@ require (
141 github.com/multiformats/go-multiaddr-dns v0.4.1 // indirect
142 github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
143 github.com/multiformats/go-multibase v0.2.0 // indirect
144 - github.com/multiformats/go-multicodec v0.10.0 // indirect
144 + github.com/multiformats/go-multicodec v0.9.2 // indirect
145 github.com/multiformats/go-multihash v0.2.3 // indirect
146 github.com/multiformats/go-multistream v0.6.1 // indirect
147 github.com/multiformats/go-varint v0.1.0 // indirect
@@ -177,7 +177,7 @@ require (
177 github.com/prometheus/common v0.66.1 // indirect
178 github.com/prometheus/procfs v0.17.0 // indirect
179 github.com/quic-go/qpack v0.5.1 // indirect
180 - github.com/quic-go/quic-go v0.55.0 // indirect
180 + github.com/quic-go/quic-go v0.54.1 // indirect
181 github.com/quic-go/webtransport-go v0.9.0 // indirect
182 github.com/rogpeppe/go-internal v1.14.1 // indirect
183 github.com/spaolacci/murmur3 v1.1.0 // indirect
@@ -212,22 +212,22 @@ require (
212 go.uber.org/zap/exp v0.3.0 // indirect
213 go.yaml.in/yaml/v2 v2.4.3 // indirect
214 go4.org v0.0.0-20230225012048-214862532bf5 // indirect
215 - golang.org/x/crypto v0.43.0 // indirect
216 - golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b // indirect
217 - golang.org/x/mod v0.29.0 // indirect
218 - golang.org/x/net v0.46.0 // indirect
215 + golang.org/x/crypto v0.42.0 // indirect
216 + golang.org/x/exp v0.0.0-20250911091902-df9299821621 // indirect
217 + golang.org/x/mod v0.28.0 // indirect
218 + golang.org/x/net v0.44.0 // indirect
219 golang.org/x/sync v0.17.0 // indirect
220 - golang.org/x/sys v0.37.0 // indirect
221 - golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect
222 - golang.org/x/text v0.30.0 // indirect
220 + golang.org/x/sys v0.36.0 // indirect
221 + golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 // indirect
222 + golang.org/x/text v0.29.0 // indirect
223 golang.org/x/time v0.12.0 // indirect
224 - golang.org/x/tools v0.38.0 // indirect
224 + golang.org/x/tools v0.37.0 // indirect
225 golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
226 gonum.org/v1/gonum v0.16.0 // indirect
227 google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
228 google.golang.org/genproto/googleapis/rpc v0.0.0-20250825161204-c5933d9347a5 // indirect
229 google.golang.org/grpc v1.75.0 // indirect
230 - google.golang.org/protobuf v1.36.10 // indirect
230 + google.golang.org/protobuf v1.36.9 // indirect
231 gopkg.in/yaml.v3 v3.0.1 // indirect
232 lukechampine.com/blake3 v1.4.1 // indirect
233 )
docs/examples/kubo-as-a-library/go.sum
+42 -38
@@ -291,8 +291,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd
291 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU=
292 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
293 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
294 -github.com/ipfs/boxo v0.35.1-0.20251016232905-37006871a40e h1:GF4HRwPWeXWJQLjkAVmN54ftHDCZ+ScP9ievuxtbx9s=
295 -github.com/ipfs/boxo v0.35.1-0.20251016232905-37006871a40e/go.mod h1:S5kJHjrzXoLDhjFVPVulE9IQnRzex9yGnG+otzF/HZg=
294 +github.com/ipfs/boxo v0.35.0 h1:3Mku5arSbAZz0dvb4goXRsQuZkFkPrGr5yYdu0YM1pY=
295 +github.com/ipfs/boxo v0.35.0/go.mod h1:uhaF0DGnbgEiXDTmD249jCGbxVkMm6+Ew85q6Uub7lo=
296 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
297 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
298 github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
@@ -321,12 +321,14 @@ github.com/ipfs/go-ds-leveldb v0.5.2 h1:6nmxlQ2zbp4LCNdJVsmHfs9GP0eylfBNxpmY1csp
321 github.com/ipfs/go-ds-leveldb v0.5.2/go.mod h1:2fAwmcvD3WoRT72PzEekHBkQmBDhc39DJGoREiuGmYo=
322 github.com/ipfs/go-ds-measure v0.2.2 h1:4kwvBGbbSXNYe4ANlg7qTIYoZU6mNlqzQHdVqICkqGI=
323 github.com/ipfs/go-ds-measure v0.2.2/go.mod h1:b/87ak0jMgH9Ylt7oH0+XGy4P8jHx9KG09Qz+pOeTIs=
324 -github.com/ipfs/go-ds-pebble v0.5.5 h1:qGlMKilJh+zy8GeizK4ZY843/3Tyf80j8t2tHVikRy0=
325 -github.com/ipfs/go-ds-pebble v0.5.5/go.mod h1:eGikA3YANvEkwSoCpXzLGQTLi3UypRBUIvvm/nwebG4=
324 +github.com/ipfs/go-ds-pebble v0.5.3 h1:4esRt82+LkenUnIWyUCghR1gzRfqeCYGGKX/hRmabro=
325 +github.com/ipfs/go-ds-pebble v0.5.3/go.mod h1:pn2bxYkAE7JRkbAF7D8xuEEFD3oOQ7QqQZPWkAVBs58=
326 github.com/ipfs/go-dsqueue v0.1.0 h1:OrahKDtT/Q+iMgKaM9XWdxrYPVASFpTuLah8QpKjboc=
327 github.com/ipfs/go-dsqueue v0.1.0/go.mod h1:iLNkodSOSKTLn0gCvL9ikArz5rZfNh8F9/BRvHe7RbY=
328 github.com/ipfs/go-fs-lock v0.1.1 h1:TecsP/Uc7WqYYatasreZQiP9EGRy4ZnKoG4yXxR33nw=
329 github.com/ipfs/go-fs-lock v0.1.1/go.mod h1:2goSXMCw7QfscHmSe09oXiR34DQeUdm+ei+dhonqly0=
330 +github.com/ipfs/go-ipfs-blockstore v1.3.1 h1:cEI9ci7V0sRNivqaOr0elDsamxXFxJMMMy7PTTDQNsQ=
331 +github.com/ipfs/go-ipfs-blockstore v1.3.1/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE=
332 github.com/ipfs/go-ipfs-cmds v0.15.0 h1:nQDgKadrzyiFyYoZMARMIoVoSwe3gGTAfGvrWLeAQbQ=
333 github.com/ipfs/go-ipfs-cmds v0.15.0/go.mod h1:VABf/mv/wqvYX6hLG6Z+40eNAEw3FQO0bSm370Or3Wk=
334 github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
@@ -349,6 +351,8 @@ github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYD
351 github.com/ipfs/go-ipld-legacy v0.2.2 h1:DThbqCPVLpWBcGtU23KDLiY2YRZZnTkXQyfz8aOfBkQ=
352 github.com/ipfs/go-ipld-legacy v0.2.2/go.mod h1:hhkj+b3kG9b2BcUNw8IFYAsfeNo8E3U7eYlWeAOPyDU=
353 github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
354 +github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8=
355 +github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo=
356 github.com/ipfs/go-log/v2 v2.8.2 h1:nVG4nNHUwwI/sTs9Bi5iE8sXFQwXs3AjkkuWhg7+Y2I=
357 github.com/ipfs/go-log/v2 v2.8.2/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c=
358 github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU=
@@ -359,15 +363,15 @@ github.com/ipfs/go-test v0.2.3 h1:Z/jXNAReQFtCYyn7bsv/ZqUwS6E7iIcSpJ2CuzCvnrc=
363 github.com/ipfs/go-test v0.2.3/go.mod h1:QW8vSKkwYvWFwIZQLGQXdkt9Ud76eQXRQ9Ao2H+cA1o=
364 github.com/ipfs/go-unixfsnode v1.10.2 h1:TREegX1J4X+k1w4AhoDuxxFvVcS9SegMRvrmxF6Tca8=
365 github.com/ipfs/go-unixfsnode v1.10.2/go.mod h1:ImDPTSiKZ+2h4UVdkSDITJHk87bUAp7kX/lgifjRicg=
362 -github.com/ipld/go-car/v2 v2.16.0 h1:LWe0vmN/QcQmUU4tr34W5Nv5mNraW+G6jfN2s+ndBco=
363 -github.com/ipld/go-car/v2 v2.16.0/go.mod h1:RqFGWN9ifcXVmCrTAVnfnxiWZk1+jIx67SYhenlmL34=
366 +github.com/ipld/go-car/v2 v2.15.0 h1:RxtZcGXFx72zFESl+UUsCNQV2YMcy3gEMYx9M3uio24=
367 +github.com/ipld/go-car/v2 v2.15.0/go.mod h1:ovlq/n3xlVJDmoiN3Kd/Z7kIzQbdTIFSwltfOP+qIgk=
368 github.com/ipld/go-codec-dagpb v1.7.0 h1:hpuvQjCSVSLnTnHXn+QAMR0mLmb1gA6wl10LExo2Ts0=
369 github.com/ipld/go-codec-dagpb v1.7.0/go.mod h1:rD3Zg+zub9ZnxcLwfol/OTQRVjaLzXypgy4UqHQvilM=
370 github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8=
371 github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
372 github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
369 -github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20250821084354-a425e60cd714 h1:cqNk8PEwHnK0vqWln+U/YZhQc9h2NB3KjUjDPZo5Q2s=
370 -github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20250821084354-a425e60cd714/go.mod h1:ZEUdra3CoqRVRYgAX/jAJO9aZGz6SKtKEG628fHHktY=
373 +github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd h1:gMlw/MhNr2Wtp5RwGdsW23cs+yCuj9k2ON7i9MiJlRo=
374 +github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd/go.mod h1:wZ8hH8UxeryOs4kJEJaiui/s00hDSbE37OKsL47g+Sw=
375 github.com/ipshipyard/p2p-forge v0.6.1 h1:987/hUC1YxI56CcMX6iTB+9BLjFV0d2SJnig9Z1pf8A=
376 github.com/ipshipyard/p2p-forge v0.6.1/go.mod h1:pj8Zcs+ex5OMq5a1bFLHqW0oL3qYO0v5eGLZmit0l7U=
377 github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
@@ -424,14 +428,14 @@ github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZ
428 github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
429 github.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784=
430 github.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo=
427 -github.com/libp2p/go-libp2p v0.44.0 h1:5Gtt8OrF8yiXmH+Mx4+/iBeFRMK1TY3a8OrEBDEqAvs=
428 -github.com/libp2p/go-libp2p v0.44.0/go.mod h1:NovCojezAt4dnDd4fH048K7PKEqH0UFYYqJRjIIu8zc=
431 +github.com/libp2p/go-libp2p v0.43.0 h1:b2bg2cRNmY4HpLK8VHYQXLX2d3iND95OjodLFymvqXU=
432 +github.com/libp2p/go-libp2p v0.43.0/go.mod h1:IiSqAXDyP2sWH+J2gs43pNmB/y4FOi2XQPbsb+8qvzc=
433 github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
434 github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
435 github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=
436 github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=
433 -github.com/libp2p/go-libp2p-kad-dht v0.35.1 h1:RQglhc9OxqDwlFFdhQMwKxIPBIBfGsleROnK5hqVsoE=
434 -github.com/libp2p/go-libp2p-kad-dht v0.35.1/go.mod h1:1oCXzkkBiYh3d5cMWLpInSOZ6am2AlpC4G+GDcZFcE0=
437 +github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251017193437-abd04263daac h1:2TWHkp8MJBLfwIRMUfvjFb2DABcjLaYAwVBzAEirkhU=
438 +github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251017193437-abd04263daac/go.mod h1:aHMTg23iseX9grGSfA5gFUzLrqzmYbA8PqgGPqM8VkI=
439 github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio=
440 github.com/libp2p/go-libp2p-kbucket v0.8.0 h1:QAK7RzKJpYe+EuSEATAaaHYMYLkPDGC18m9jxPLnU8s=
441 github.com/libp2p/go-libp2p-kbucket v0.8.0/go.mod h1:JMlxqcEyKwO6ox716eyC0hmiduSWZZl6JY93mGaaqc4=
@@ -451,8 +455,8 @@ github.com/libp2p/go-libp2p-xor v0.1.0/go.mod h1:LSTM5yRnjGZbWNTA/hRwq2gGFrvRIbQ
455 github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
456 github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=
457 github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=
454 -github.com/libp2p/go-netroute v0.3.0 h1:nqPCXHmeNmgTJnktosJ/sIef9hvwYCrsLxXmfNks/oc=
455 -github.com/libp2p/go-netroute v0.3.0/go.mod h1:Nkd5ShYgSMS5MUKy/MU2T57xFoOKvvLR92Lic48LEyA=
458 +github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8=
459 +github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE=
460 github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
461 github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
462 github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s=
@@ -465,8 +469,6 @@ github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm
469 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
470 github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
471 github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
468 -github.com/marcopolo/simnet v0.0.1 h1:rSMslhPz6q9IvJeFWDoMGxMIrlsbXau3NkuIXHGJxfg=
469 -github.com/marcopolo/simnet v0.0.1/go.mod h1:WDaQkgLAjqDUEBAOXz22+1j6wXKfGlC5sD5XWt3ddOs=
472 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
473 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
474 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -527,8 +529,8 @@ github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/g
529 github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
530 github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
531 github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
530 -github.com/multiformats/go-multicodec v0.10.0 h1:UpP223cig/Cx8J76jWt91njpK3GTAO1w02sdcjZDSuc=
531 -github.com/multiformats/go-multicodec v0.10.0/go.mod h1:wg88pM+s2kZJEQfRCKBNU+g32F5aWBEjyFHXvZLTcLI=
532 +github.com/multiformats/go-multicodec v0.9.2 h1:YrlXCuqxjqm3bXl+vBq5LKz5pz4mvAsugdqy78k0pXQ=
533 +github.com/multiformats/go-multicodec v0.9.2/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy+h3EbkMTek1m+Fybbo=
534 github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
535 github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
536 github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
@@ -647,8 +649,8 @@ github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7D
649 github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
650 github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
651 github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
650 -github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
651 -github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
652 +github.com/quic-go/quic-go v0.54.1 h1:4ZAWm0AhCb6+hE+l5Q1NAL0iRn/ZrMwqHRGQiFwj2eg=
653 +github.com/quic-go/quic-go v0.54.1/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
654 github.com/quic-go/webtransport-go v0.9.0 h1:jgys+7/wm6JarGDrW+lD/r9BGqBAmqY/ssklE09bA70=
655 github.com/quic-go/webtransport-go v0.9.0/go.mod h1:4FUYIiUc75XSsF6HShcLeXXYZJ9AGwo/xh3L8M/P1ao=
656 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@@ -803,6 +805,8 @@ go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJr
805 go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
806 go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
807 go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
808 +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
809 +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
810 go.uber.org/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4=
811 go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
812 go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg=
@@ -842,8 +846,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
846 golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
847 golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
848 golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
845 -golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
846 -golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
849 +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
850 +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
851 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
852 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
853 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -852,8 +856,8 @@ golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE
856 golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
857 golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
858 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
855 -golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b h1:18qgiDvlvH7kk8Ioa8Ov+K6xCi0GMvmGfGW0sgd/SYA=
856 -golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
859 +golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU=
860 +golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
861 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
862 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
863 golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -876,8 +880,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
880 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
881 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
882 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
879 -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
880 -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
883 +golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
884 +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
885 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
886 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
887 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -913,8 +917,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
917 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
918 golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
919 golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
916 -golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
917 -golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
920 +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
921 +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
922 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
923 golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
924 golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -981,10 +985,10 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
985 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
986 golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
987 golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
984 -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
985 -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
986 -golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=
987 -golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
988 +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
989 +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
990 +golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 h1:dHQOQddU4YHS5gY33/6klKjq7Gp3WwMyOXGNp5nzRj8=
991 +golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE=
992 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
993 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
994 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1004,8 +1008,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
1008 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
1009 golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
1010 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
1007 -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
1008 -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
1011 +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
1012 +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
1013 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
1014 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
1015 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1046,8 +1050,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
1050 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
1051 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
1052 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
1049 -golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
1050 -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
1053 +golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
1054 +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
1055 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
1056 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
1057 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1122,8 +1126,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
1126 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
1127 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
1128 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
1125 -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
1126 -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
1129 +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
1130 +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
1131 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1132 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1133 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
docs/provide-stats.md new
+188
@@ -0,0 +1,188 @@
1 +# Provide Stats
2 +
3 +The `ipfs provide stat` command gives you statistics about your local provide
4 +system. This file provides a detailed explanation of the metrics reported by
5 +this command.
6 +
7 +## Connectivity
8 +
9 +### Status
10 +
11 +Current connectivity status (`online`, `disconnected`, or `offline`) and when
12 +it last changed (see [provide connectivity
13 +status](./config.md#providedhtofflinedelay)).
14 +
15 +## Queues
16 +
17 +### Provide queue
18 +
19 +Number of CIDs waiting for initial provide, and the number of keyspace regions
20 +they're grouped into.
21 +
22 +### Reprovide queue
23 +
24 +Number of regions with overdue reprovides. These regions missed their scheduled
25 +reprovide time and will be processed as soon as possible. If decreasing, the
26 +node is recovering from downtime. If increasing, either the node is offline or
27 +the provide system needs more workers (see
28 +[`Provide.DHT.MaxWorkers`](./config.md#providedhtmaxworkers)
29 +and
30 +[`Provide.DHT.DedicatedPeriodicWorkers`](./config.md#providedhtdedicatedperiodicworkers)).
31 +
32 +## Schedule
33 +
34 +### CIDs scheduled
35 +
36 +Total CIDs scheduled for reprovide.
37 +
38 +### Regions scheduled
39 +
40 +Number of keyspace regions scheduled for reprovide. Each CID is mapped to a
41 +specific region, and all CIDs within the same region are reprovided together as
42 +a batch for efficient processing.
43 +
44 +### Avg prefix length
45 +
46 +Average length of binary prefixes identifying the scheduled regions. Each
47 +keyspace region is identified by a binary prefix, and this shows the average
48 +prefix length across all regions in the schedule. Longer prefixes indicate more
49 +DHT servers in the swarm.
50 +
51 +### Next region prefix
52 +
53 +Keyspace prefix of the next region to be reprovided.
54 +
55 +### Next region reprovide
56 +
57 +When the next region is scheduled to be reprovided.
58 +
59 +## Timings
60 +
61 +### Uptime
62 +
63 +How long the provide system has been running since Kubo started, along with the
64 +start timestamp.
65 +
66 +### Current time offset
67 +
68 +Elapsed time in the current reprovide cycle, showing cycle progress.
69 +
70 +### Cycle started
71 +
72 +When the current reprovide cycle began.
73 +
74 +### Reprovide interval
75 +
76 +How often each CID is reprovided (the complete cycle duration).
77 +
78 +## Network
79 +
80 +### Avg record holders
81 +
82 +Average number of provider records successfully sent for each CID to distinct
83 +DHT servers. In practice, this is often lower than the [replication
84 +factor](#replication-factor) due to unreachable peers or timeouts. Matching the
85 +replication factor would indicate all DHT servers are reachable.
86 +
87 +Note: some holders may have gone offline since receiving the record.
88 +
89 +### Peers swept
90 +
91 +Number of DHT servers to which we tried to send provider records in the last
92 +reprovide cycle (sweep). Excludes peers contacted during initial provides or
93 +DHT lookups.
94 +
95 +### Full keyspace coverage
96 +
97 +Whether provider records were sent to all DHT servers in the swarm during the
98 +last reprovide cycle. If true, [peers swept](#peers-swept) approximates the
99 +total DHT swarm size over the last [reprovide interval](#reprovide-interval).
100 +
101 +### Reachable peers
102 +
103 +Number and percentage of peers to which we successfully sent all provider
104 +records assigned to them during the last reprovide cycle.
105 +
106 +### Avg region size
107 +
108 +Average number of DHT servers per keyspace region.
109 +
110 +### Replication factor
111 +
112 +Target number of DHT servers to receive each provider record.
113 +
114 +## Operations
115 +
116 +### Ongoing provides
117 +
118 +Number of CIDs and regions currently being provided for the first time. More
119 +CIDs than regions indicates efficient batching. Each region provide uses a
120 +[burst
121 +worker](./config.md#providedhtdedicatedburstworkers).
122 +
123 +### Ongoing reprovides
124 +
125 +Number of CIDs and regions currently being reprovided. Each region reprovide
126 +uses a [periodic
127 +worker](./config.md#providedhtdedicatedperiodicworkers).
128 +
129 +### Total CIDs provided
130 +
131 +Total number of provide operations since node startup (includes both provides
132 +and reprovides).
133 +
134 +### Total records provided
135 +
136 +Total provider records successfully sent to DHT servers since startup (includes
137 +reprovides).
138 +
139 +### Total provide errors
140 +
141 +Number of failed region provide/reprovide operations since startup. Failed
142 +regions are automatically retried unless the node is offline.
143 +
144 +### CIDs provided/min
145 +
146 +Average rate of initial provides per minute during the last reprovide cycle
147 +(excludes reprovides).
148 +
149 +### CIDs reprovided/min
150 +
151 +Average rate of reprovides per minute during the last reprovide cycle (excludes
152 +initial provides).
153 +
154 +### Region reprovide duration
155 +
156 +Average time to reprovide all CIDs in a region during the last cycle.
157 +
158 +### Avg CIDs/reprovide
159 +
160 +Average number of CIDs per region during the last reprovide cycle.
161 +
162 +### Regions reprovided (last cycle)
163 +
164 +Number of regions reprovided in the last cycle.
165 +
166 +## Workers
167 +
168 +### Active workers
169 +
170 +Number of workers currently processing provide or reprovide operations.
171 +
172 +### Free workers
173 +
174 +Number of idle workers not reserved for periodic or burst tasks.
175 +
176 +### Workers stats
177 +
178 +Breakdown of worker status by type (periodic for scheduled reprovides, burst
179 +for initial provides). For each: active (currently processing), dedicated
180 +(reserved for this type), available (idle dedicated + [free
181 +workers](#free-workers)), and queued (0 or 1, since we only acquire when
182 +needed). See [provide queue](#provide-queue) and [reprovide
183 +queue](#reprovide-queue) for regions waiting to be processed.
184 +
185 +### Max connections/worker
186 +
187 +Maximum concurrent DHT server connections per worker when sending provider
188 +records for a region.
go.mod
+20 -20
@@ -22,7 +22,7 @@ require (
22 github.com/hashicorp/go-version v1.7.0
23 github.com/ipfs-shipyard/nopfs v0.0.14
24 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0
25 - github.com/ipfs/boxo v0.35.1-0.20251016232905-37006871a40e
25 + github.com/ipfs/boxo v0.35.0
26 github.com/ipfs/go-block-format v0.2.3
27 github.com/ipfs/go-cid v0.5.0
28 github.com/ipfs/go-cidutil v0.1.0
@@ -32,7 +32,7 @@ require (
32 github.com/ipfs/go-ds-flatfs v0.5.5
33 github.com/ipfs/go-ds-leveldb v0.5.2
34 github.com/ipfs/go-ds-measure v0.2.2
35 - github.com/ipfs/go-ds-pebble v0.5.5
35 + github.com/ipfs/go-ds-pebble v0.5.3
36 github.com/ipfs/go-fs-lock v0.1.1
37 github.com/ipfs/go-ipfs-cmds v0.15.0
38 github.com/ipfs/go-ipld-cbor v0.2.1
@@ -44,16 +44,16 @@ require (
44 github.com/ipfs/go-metrics-prometheus v0.1.0
45 github.com/ipfs/go-test v0.2.3
46 github.com/ipfs/go-unixfsnode v1.10.2
47 - github.com/ipld/go-car/v2 v2.16.0
47 + github.com/ipld/go-car/v2 v2.15.0
48 github.com/ipld/go-codec-dagpb v1.7.0
49 github.com/ipld/go-ipld-prime v0.21.0
50 github.com/ipshipyard/p2p-forge v0.6.1
51 github.com/jbenet/go-temp-err-catcher v0.1.0
52 github.com/julienschmidt/httprouter v1.3.0
53 github.com/libp2p/go-doh-resolver v0.5.0
54 - github.com/libp2p/go-libp2p v0.44.0
54 + github.com/libp2p/go-libp2p v0.43.0
55 github.com/libp2p/go-libp2p-http v0.5.0
56 - github.com/libp2p/go-libp2p-kad-dht v0.35.1
56 + github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251017193437-abd04263daac
57 github.com/libp2p/go-libp2p-kbucket v0.8.0
58 github.com/libp2p/go-libp2p-pubsub v0.14.2
59 github.com/libp2p/go-libp2p-pubsub-router v0.6.0
@@ -65,10 +65,11 @@ require (
65 github.com/multiformats/go-multiaddr v0.16.1
66 github.com/multiformats/go-multiaddr-dns v0.4.1
67 github.com/multiformats/go-multibase v0.2.0
68 - github.com/multiformats/go-multicodec v0.10.0
68 + github.com/multiformats/go-multicodec v0.9.2
69 github.com/multiformats/go-multihash v0.2.3
70 github.com/opentracing/opentracing-go v1.2.0
71 github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58
72 + github.com/probe-lab/go-libdht v0.3.0
73 github.com/prometheus/client_golang v1.23.2
74 github.com/stretchr/testify v1.11.1
75 github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d
@@ -87,12 +88,12 @@ require (
88 go.uber.org/dig v1.19.0
89 go.uber.org/fx v1.24.0
90 go.uber.org/zap v1.27.0
90 - golang.org/x/crypto v0.43.0
91 - golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b
92 - golang.org/x/mod v0.29.0
91 + golang.org/x/crypto v0.42.0
92 + golang.org/x/exp v0.0.0-20250911091902-df9299821621
93 + golang.org/x/mod v0.28.0
94 golang.org/x/sync v0.17.0
94 - golang.org/x/sys v0.37.0
95 - google.golang.org/protobuf v1.36.10
95 + golang.org/x/sys v0.36.0
96 + google.golang.org/protobuf v1.36.9
97 )
98
99 require (
@@ -169,7 +170,7 @@ require (
170 github.com/libp2p/go-libp2p-gostream v0.6.0 // indirect
171 github.com/libp2p/go-libp2p-xor v0.1.0 // indirect
172 github.com/libp2p/go-msgio v0.3.0 // indirect
172 - github.com/libp2p/go-netroute v0.3.0 // indirect
173 + github.com/libp2p/go-netroute v0.2.2 // indirect
174 github.com/libp2p/go-reuseport v0.4.0 // indirect
175 github.com/libp2p/go-yamux/v5 v5.0.1 // indirect
176 github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
@@ -215,13 +216,12 @@ require (
216 github.com/pkg/errors v0.9.1 // indirect
217 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
218 github.com/polydawn/refmt v0.89.0 // indirect
218 - github.com/probe-lab/go-libdht v0.3.0 // indirect
219 github.com/prometheus/client_model v0.6.2 // indirect
220 github.com/prometheus/common v0.66.1 // indirect
221 github.com/prometheus/procfs v0.17.0 // indirect
222 github.com/prometheus/statsd_exporter v0.27.1 // indirect
223 github.com/quic-go/qpack v0.5.1 // indirect
224 - github.com/quic-go/quic-go v0.55.0 // indirect
224 + github.com/quic-go/quic-go v0.54.1 // indirect
225 github.com/quic-go/webtransport-go v0.9.0 // indirect
226 github.com/rivo/uniseg v0.4.4 // indirect
227 github.com/rogpeppe/go-internal v1.14.1 // indirect
@@ -256,13 +256,13 @@ require (
256 go.uber.org/zap/exp v0.3.0 // indirect
257 go.yaml.in/yaml/v2 v2.4.3 // indirect
258 go4.org v0.0.0-20230225012048-214862532bf5 // indirect
259 - golang.org/x/net v0.46.0 // indirect
260 - golang.org/x/oauth2 v0.32.0 // indirect
261 - golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect
262 - golang.org/x/term v0.36.0 // indirect
263 - golang.org/x/text v0.30.0 // indirect
259 + golang.org/x/net v0.44.0 // indirect
260 + golang.org/x/oauth2 v0.31.0 // indirect
261 + golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 // indirect
262 + golang.org/x/term v0.35.0 // indirect
263 + golang.org/x/text v0.29.0 // indirect
264 golang.org/x/time v0.12.0 // indirect
265 - golang.org/x/tools v0.38.0 // indirect
265 + golang.org/x/tools v0.37.0 // indirect
266 golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
267 gonum.org/v1/gonum v0.16.0 // indirect
268 google.golang.org/genproto/googleapis/api v0.0.0-20250825161204-c5933d9347a5 // indirect
go.sum
+46 -42
@@ -358,8 +358,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd
358 github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU=
359 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
360 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
361 -github.com/ipfs/boxo v0.35.1-0.20251016232905-37006871a40e h1:GF4HRwPWeXWJQLjkAVmN54ftHDCZ+ScP9ievuxtbx9s=
362 -github.com/ipfs/boxo v0.35.1-0.20251016232905-37006871a40e/go.mod h1:S5kJHjrzXoLDhjFVPVulE9IQnRzex9yGnG+otzF/HZg=
361 +github.com/ipfs/boxo v0.35.0 h1:3Mku5arSbAZz0dvb4goXRsQuZkFkPrGr5yYdu0YM1pY=
362 +github.com/ipfs/boxo v0.35.0/go.mod h1:uhaF0DGnbgEiXDTmD249jCGbxVkMm6+Ew85q6Uub7lo=
363 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
364 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
365 github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
@@ -388,12 +388,14 @@ github.com/ipfs/go-ds-leveldb v0.5.2 h1:6nmxlQ2zbp4LCNdJVsmHfs9GP0eylfBNxpmY1csp
388 github.com/ipfs/go-ds-leveldb v0.5.2/go.mod h1:2fAwmcvD3WoRT72PzEekHBkQmBDhc39DJGoREiuGmYo=
389 github.com/ipfs/go-ds-measure v0.2.2 h1:4kwvBGbbSXNYe4ANlg7qTIYoZU6mNlqzQHdVqICkqGI=
390 github.com/ipfs/go-ds-measure v0.2.2/go.mod h1:b/87ak0jMgH9Ylt7oH0+XGy4P8jHx9KG09Qz+pOeTIs=
391 -github.com/ipfs/go-ds-pebble v0.5.5 h1:qGlMKilJh+zy8GeizK4ZY843/3Tyf80j8t2tHVikRy0=
392 -github.com/ipfs/go-ds-pebble v0.5.5/go.mod h1:eGikA3YANvEkwSoCpXzLGQTLi3UypRBUIvvm/nwebG4=
391 +github.com/ipfs/go-ds-pebble v0.5.3 h1:4esRt82+LkenUnIWyUCghR1gzRfqeCYGGKX/hRmabro=
392 +github.com/ipfs/go-ds-pebble v0.5.3/go.mod h1:pn2bxYkAE7JRkbAF7D8xuEEFD3oOQ7QqQZPWkAVBs58=
393 github.com/ipfs/go-dsqueue v0.1.0 h1:OrahKDtT/Q+iMgKaM9XWdxrYPVASFpTuLah8QpKjboc=
394 github.com/ipfs/go-dsqueue v0.1.0/go.mod h1:iLNkodSOSKTLn0gCvL9ikArz5rZfNh8F9/BRvHe7RbY=
395 github.com/ipfs/go-fs-lock v0.1.1 h1:TecsP/Uc7WqYYatasreZQiP9EGRy4ZnKoG4yXxR33nw=
396 github.com/ipfs/go-fs-lock v0.1.1/go.mod h1:2goSXMCw7QfscHmSe09oXiR34DQeUdm+ei+dhonqly0=
397 +github.com/ipfs/go-ipfs-blockstore v1.3.1 h1:cEI9ci7V0sRNivqaOr0elDsamxXFxJMMMy7PTTDQNsQ=
398 +github.com/ipfs/go-ipfs-blockstore v1.3.1/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE=
399 github.com/ipfs/go-ipfs-cmds v0.15.0 h1:nQDgKadrzyiFyYoZMARMIoVoSwe3gGTAfGvrWLeAQbQ=
400 github.com/ipfs/go-ipfs-cmds v0.15.0/go.mod h1:VABf/mv/wqvYX6hLG6Z+40eNAEw3FQO0bSm370Or3Wk=
401 github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
@@ -416,6 +418,8 @@ github.com/ipfs/go-ipld-git v0.1.1/go.mod h1:+VyMqF5lMcJh4rwEppV0e6g4nCCHXThLYYD
418 github.com/ipfs/go-ipld-legacy v0.2.2 h1:DThbqCPVLpWBcGtU23KDLiY2YRZZnTkXQyfz8aOfBkQ=
419 github.com/ipfs/go-ipld-legacy v0.2.2/go.mod h1:hhkj+b3kG9b2BcUNw8IFYAsfeNo8E3U7eYlWeAOPyDU=
420 github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
421 +github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8=
422 +github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo=
423 github.com/ipfs/go-log/v2 v2.8.2 h1:nVG4nNHUwwI/sTs9Bi5iE8sXFQwXs3AjkkuWhg7+Y2I=
424 github.com/ipfs/go-log/v2 v2.8.2/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c=
425 github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU=
@@ -428,15 +432,15 @@ github.com/ipfs/go-test v0.2.3 h1:Z/jXNAReQFtCYyn7bsv/ZqUwS6E7iIcSpJ2CuzCvnrc=
432 github.com/ipfs/go-test v0.2.3/go.mod h1:QW8vSKkwYvWFwIZQLGQXdkt9Ud76eQXRQ9Ao2H+cA1o=
433 github.com/ipfs/go-unixfsnode v1.10.2 h1:TREegX1J4X+k1w4AhoDuxxFvVcS9SegMRvrmxF6Tca8=
434 github.com/ipfs/go-unixfsnode v1.10.2/go.mod h1:ImDPTSiKZ+2h4UVdkSDITJHk87bUAp7kX/lgifjRicg=
431 -github.com/ipld/go-car/v2 v2.16.0 h1:LWe0vmN/QcQmUU4tr34W5Nv5mNraW+G6jfN2s+ndBco=
432 -github.com/ipld/go-car/v2 v2.16.0/go.mod h1:RqFGWN9ifcXVmCrTAVnfnxiWZk1+jIx67SYhenlmL34=
435 +github.com/ipld/go-car/v2 v2.15.0 h1:RxtZcGXFx72zFESl+UUsCNQV2YMcy3gEMYx9M3uio24=
436 +github.com/ipld/go-car/v2 v2.15.0/go.mod h1:ovlq/n3xlVJDmoiN3Kd/Z7kIzQbdTIFSwltfOP+qIgk=
437 github.com/ipld/go-codec-dagpb v1.7.0 h1:hpuvQjCSVSLnTnHXn+QAMR0mLmb1gA6wl10LExo2Ts0=
438 github.com/ipld/go-codec-dagpb v1.7.0/go.mod h1:rD3Zg+zub9ZnxcLwfol/OTQRVjaLzXypgy4UqHQvilM=
439 github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8=
440 github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
441 github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
438 -github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20250821084354-a425e60cd714 h1:cqNk8PEwHnK0vqWln+U/YZhQc9h2NB3KjUjDPZo5Q2s=
439 -github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20250821084354-a425e60cd714/go.mod h1:ZEUdra3CoqRVRYgAX/jAJO9aZGz6SKtKEG628fHHktY=
442 +github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd h1:gMlw/MhNr2Wtp5RwGdsW23cs+yCuj9k2ON7i9MiJlRo=
443 +github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd/go.mod h1:wZ8hH8UxeryOs4kJEJaiui/s00hDSbE37OKsL47g+Sw=
444 github.com/ipshipyard/p2p-forge v0.6.1 h1:987/hUC1YxI56CcMX6iTB+9BLjFV0d2SJnig9Z1pf8A=
445 github.com/ipshipyard/p2p-forge v0.6.1/go.mod h1:pj8Zcs+ex5OMq5a1bFLHqW0oL3qYO0v5eGLZmit0l7U=
446 github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
@@ -504,8 +508,8 @@ github.com/libp2p/go-flow-metrics v0.0.1/go.mod h1:Iv1GH0sG8DtYN3SVJ2eG221wMiNpZ
508 github.com/libp2p/go-flow-metrics v0.0.3/go.mod h1:HeoSNUrOJVK1jEpDqVEiUOIXqhbnS27omG0uWU5slZs=
509 github.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784=
510 github.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo=
507 -github.com/libp2p/go-libp2p v0.44.0 h1:5Gtt8OrF8yiXmH+Mx4+/iBeFRMK1TY3a8OrEBDEqAvs=
508 -github.com/libp2p/go-libp2p v0.44.0/go.mod h1:NovCojezAt4dnDd4fH048K7PKEqH0UFYYqJRjIIu8zc=
511 +github.com/libp2p/go-libp2p v0.43.0 h1:b2bg2cRNmY4HpLK8VHYQXLX2d3iND95OjodLFymvqXU=
512 +github.com/libp2p/go-libp2p v0.43.0/go.mod h1:IiSqAXDyP2sWH+J2gs43pNmB/y4FOi2XQPbsb+8qvzc=
513 github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
514 github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
515 github.com/libp2p/go-libp2p-core v0.2.4/go.mod h1:STh4fdfa5vDYr0/SzYYeqnt+E6KfEV5VxfIrm0bcI0g=
@@ -514,8 +518,8 @@ github.com/libp2p/go-libp2p-gostream v0.6.0 h1:QfAiWeQRce6pqnYfmIVWJFXNdDyfiR/qk
518 github.com/libp2p/go-libp2p-gostream v0.6.0/go.mod h1:Nywu0gYZwfj7Jc91PQvbGU8dIpqbQQkjWgDuOrFaRdA=
519 github.com/libp2p/go-libp2p-http v0.5.0 h1:+x0AbLaUuLBArHubbbNRTsgWz0RjNTy6DJLOxQ3/QBc=
520 github.com/libp2p/go-libp2p-http v0.5.0/go.mod h1:glh87nZ35XCQyFsdzZps6+F4HYI6DctVFY5u1fehwSg=
517 -github.com/libp2p/go-libp2p-kad-dht v0.35.1 h1:RQglhc9OxqDwlFFdhQMwKxIPBIBfGsleROnK5hqVsoE=
518 -github.com/libp2p/go-libp2p-kad-dht v0.35.1/go.mod h1:1oCXzkkBiYh3d5cMWLpInSOZ6am2AlpC4G+GDcZFcE0=
521 +github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251017193437-abd04263daac h1:2TWHkp8MJBLfwIRMUfvjFb2DABcjLaYAwVBzAEirkhU=
522 +github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251017193437-abd04263daac/go.mod h1:aHMTg23iseX9grGSfA5gFUzLrqzmYbA8PqgGPqM8VkI=
523 github.com/libp2p/go-libp2p-kbucket v0.3.1/go.mod h1:oyjT5O7tS9CQurok++ERgc46YLwEpuGoFq9ubvoUOio=
524 github.com/libp2p/go-libp2p-kbucket v0.8.0 h1:QAK7RzKJpYe+EuSEATAaaHYMYLkPDGC18m9jxPLnU8s=
525 github.com/libp2p/go-libp2p-kbucket v0.8.0/go.mod h1:JMlxqcEyKwO6ox716eyC0hmiduSWZZl6JY93mGaaqc4=
@@ -535,8 +539,8 @@ github.com/libp2p/go-libp2p-xor v0.1.0/go.mod h1:LSTM5yRnjGZbWNTA/hRwq2gGFrvRIbQ
539 github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
540 github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=
541 github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=
538 -github.com/libp2p/go-netroute v0.3.0 h1:nqPCXHmeNmgTJnktosJ/sIef9hvwYCrsLxXmfNks/oc=
539 -github.com/libp2p/go-netroute v0.3.0/go.mod h1:Nkd5ShYgSMS5MUKy/MU2T57xFoOKvvLR92Lic48LEyA=
542 +github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8=
543 +github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE=
544 github.com/libp2p/go-openssl v0.0.3/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
545 github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
546 github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s=
@@ -551,8 +555,6 @@ github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm
555 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
556 github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
557 github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
554 -github.com/marcopolo/simnet v0.0.1 h1:rSMslhPz6q9IvJeFWDoMGxMIrlsbXau3NkuIXHGJxfg=
555 -github.com/marcopolo/simnet v0.0.1/go.mod h1:WDaQkgLAjqDUEBAOXz22+1j6wXKfGlC5sD5XWt3ddOs=
558 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
559 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
560 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -626,8 +628,8 @@ github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/g
628 github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
629 github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
630 github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
629 -github.com/multiformats/go-multicodec v0.10.0 h1:UpP223cig/Cx8J76jWt91njpK3GTAO1w02sdcjZDSuc=
630 -github.com/multiformats/go-multicodec v0.10.0/go.mod h1:wg88pM+s2kZJEQfRCKBNU+g32F5aWBEjyFHXvZLTcLI=
631 +github.com/multiformats/go-multicodec v0.9.2 h1:YrlXCuqxjqm3bXl+vBq5LKz5pz4mvAsugdqy78k0pXQ=
632 +github.com/multiformats/go-multicodec v0.9.2/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy+h3EbkMTek1m+Fybbo=
633 github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
634 github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
635 github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
@@ -773,8 +775,8 @@ github.com/prometheus/statsd_exporter v0.27.1 h1:tcRJOmwlA83HPfWzosAgr2+zEN5XDFv
775 github.com/prometheus/statsd_exporter v0.27.1/go.mod h1:vA6ryDfsN7py/3JApEst6nLTJboq66XsNcJGNmC88NQ=
776 github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
777 github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
776 -github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
777 -github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
778 +github.com/quic-go/quic-go v0.54.1 h1:4ZAWm0AhCb6+hE+l5Q1NAL0iRn/ZrMwqHRGQiFwj2eg=
779 +github.com/quic-go/quic-go v0.54.1/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
780 github.com/quic-go/webtransport-go v0.9.0 h1:jgys+7/wm6JarGDrW+lD/r9BGqBAmqY/ssklE09bA70=
781 github.com/quic-go/webtransport-go v0.9.0/go.mod h1:4FUYIiUc75XSsF6HShcLeXXYZJ9AGwo/xh3L8M/P1ao=
782 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
@@ -968,6 +970,8 @@ go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJr
970 go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
971 go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
972 go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
973 +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
974 +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
975 go.uber.org/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4=
976 go.uber.org/dig v1.19.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
977 go.uber.org/fx v1.24.0 h1:wE8mruvpg2kiiL1Vqd0CC+tr0/24XIB10Iwp2lLWzkg=
@@ -1007,8 +1011,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
1011 golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
1012 golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
1013 golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
1010 -golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
1011 -golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
1014 +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
1015 +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
1016 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
1017 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
1018 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1019,8 +1023,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
1023 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
1024 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
1025 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
1022 -golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b h1:18qgiDvlvH7kk8Ioa8Ov+K6xCi0GMvmGfGW0sgd/SYA=
1023 -golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
1026 +golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU=
1027 +golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
1028 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
1029 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
1030 golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -1044,8 +1048,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
1048 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
1049 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
1050 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
1047 -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
1048 -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
1051 +golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
1052 +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
1053 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
1054 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
1055 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1097,8 +1101,8 @@ golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
1101 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
1102 golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
1103 golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
1100 -golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
1101 -golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
1104 +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
1105 +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
1106 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
1107 golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
1108 golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1108,8 +1112,8 @@ golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4Iltr
1112 golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
1113 golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
1114 golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
1111 -golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
1112 -golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
1115 +golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo=
1116 +golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
1117 golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw=
1118 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
1119 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -1194,10 +1198,10 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1198 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1199 golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1200 golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
1197 -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
1198 -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
1199 -golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=
1200 -golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
1201 +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
1202 +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
1203 +golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 h1:dHQOQddU4YHS5gY33/6klKjq7Gp3WwMyOXGNp5nzRj8=
1204 +golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE=
1205 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
1206 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
1207 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -1206,8 +1210,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
1210 golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
1211 golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
1212 golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
1209 -golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
1210 -golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
1213 +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
1214 +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
1215 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
1216 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
1217 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1219,8 +1223,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
1223 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
1224 golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
1225 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
1222 -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
1223 -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
1226 +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
1227 +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
1228 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
1229 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
1230 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1278,8 +1282,8 @@ golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4f
1282 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
1283 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
1284 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
1281 -golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
1282 -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
1285 +golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
1286 +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
1287 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
1288 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
1289 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1385,8 +1389,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0
1389 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
1390 google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
1391 google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
1388 -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
1389 -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
1392 +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
1393 +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
1394 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
1395 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1396 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
test/cli/provide_stats_test.go new
+524
@@ -0,0 +1,524 @@
1 +package cli
2 +
3 +import (
4 + "bufio"
5 + "encoding/json"
6 + "os"
7 + "path/filepath"
8 + "strings"
9 + "testing"
10 + "time"
11 +
12 + "github.com/ipfs/kubo/test/cli/harness"
13 + "github.com/stretchr/testify/assert"
14 + "github.com/stretchr/testify/require"
15 +)
16 +
17 +const (
18 + provideStatEventuallyTimeout = 15 * time.Second
19 + provideStatEventuallyTick = 100 * time.Millisecond
20 +)
21 +
22 +// sweepStats mirrors the subset of JSON fields actually used by tests.
23 +// This type is intentionally independent from upstream types to detect breaking changes.
24 +// Only includes fields that tests actually access to keep it simple and maintainable.
25 +type sweepStats struct {
26 + Sweep struct {
27 + Closed bool `json:"closed"`
28 + Connectivity struct {
29 + Status string `json:"status"`
30 + } `json:"connectivity"`
31 + Queues struct {
32 + PendingKeyProvides int `json:"pending_key_provides"`
33 + } `json:"queues"`
34 + Schedule struct {
35 + Keys int `json:"keys"`
36 + } `json:"schedule"`
37 + } `json:"Sweep"`
38 +}
39 +
40 +// parseSweepStats parses JSON output from ipfs provide stat command.
41 +// Tests will naturally fail if upstream removes/renames fields we depend on.
42 +func parseSweepStats(t *testing.T, jsonOutput string) sweepStats {
43 + t.Helper()
44 + var stats sweepStats
45 + err := json.Unmarshal([]byte(jsonOutput), &stats)
46 + require.NoError(t, err, "failed to parse provide stat JSON output")
47 + return stats
48 +}
49 +
50 +// TestProvideStatAllMetricsDocumented verifies that all metrics output by
51 +// `ipfs provide stat --all` are documented in docs/provide-stats.md.
52 +//
53 +// The test works as follows:
54 +// 1. Starts an IPFS node with Provide.DHT.SweepEnabled=true
55 +// 2. Runs `ipfs provide stat --all` to get all metrics
56 +// 3. Parses the output and extracts all lines with exactly 2 spaces indent
57 +// (these are the actual metric lines)
58 +// 4. Reads docs/provide-stats.md and extracts all ### section headers
59 +// 5. Ensures every metric in the output has a corresponding ### section in the docs
60 +func TestProvideStatAllMetricsDocumented(t *testing.T) {
61 + t.Parallel()
62 +
63 + h := harness.NewT(t)
64 + node := h.NewNode().Init()
65 +
66 + // Enable sweep provider
67 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", true)
68 + node.SetIPFSConfig("Provide.Enabled", true)
69 +
70 + node.StartDaemon()
71 + defer node.StopDaemon()
72 +
73 + // Run `ipfs provide stat --all` to get all metrics
74 + res := node.IPFS("provide", "stat", "--all")
75 + require.NoError(t, res.Err)
76 +
77 + // Parse metrics from the command output
78 + // Only consider lines with exactly two spaces of padding (" ")
79 + // These are the actual metric lines as shown in provide.go
80 + outputMetrics := make(map[string]bool)
81 + scanner := bufio.NewScanner(strings.NewReader(res.Stdout.String()))
82 + // Only consider lines that start with exactly two spaces
83 + indent := " "
84 + for scanner.Scan() {
85 + line := scanner.Text()
86 + if !strings.HasPrefix(line, indent) || strings.HasPrefix(line, indent) {
87 + continue
88 + }
89 +
90 + // Remove the indent
91 + line = strings.TrimPrefix(line, indent)
92 +
93 + // Extract metric name - everything before the first ':'
94 + parts := strings.SplitN(line, ":", 2)
95 + if len(parts) >= 1 {
96 + metricName := strings.TrimSpace(parts[0])
97 + if metricName != "" {
98 + outputMetrics[metricName] = true
99 + }
100 + }
101 + }
102 + require.NoError(t, scanner.Err())
103 +
104 + // Read docs/provide-stats.md
105 + // Find the repo root by looking for go.mod
106 + repoRoot := ".."
107 + for range 6 {
108 + if _, err := os.Stat(filepath.Join(repoRoot, "go.mod")); err == nil {
109 + break
110 + }
111 + repoRoot = filepath.Join("..", repoRoot)
112 + }
113 + docsPath := filepath.Join(repoRoot, "docs", "provide-stats.md")
114 + docsFile, err := os.Open(docsPath)
115 + require.NoError(t, err, "Failed to open provide-stats.md")
116 + defer docsFile.Close()
117 +
118 + // Parse all ### metric headers from the docs
119 + documentedMetrics := make(map[string]bool)
120 + docsScanner := bufio.NewScanner(docsFile)
121 + for docsScanner.Scan() {
122 + line := docsScanner.Text()
123 + if metricName, found := strings.CutPrefix(line, "### "); found {
124 + metricName = strings.TrimSpace(metricName)
125 + documentedMetrics[metricName] = true
126 + }
127 + }
128 + require.NoError(t, docsScanner.Err())
129 +
130 + // Check that all output metrics are documented
131 + var undocumentedMetrics []string
132 + for metric := range outputMetrics {
133 + if !documentedMetrics[metric] {
134 + undocumentedMetrics = append(undocumentedMetrics, metric)
135 + }
136 + }
137 +
138 + require.Empty(t, undocumentedMetrics,
139 + "The following metrics from 'ipfs provide stat --all' are not documented in docs/provide-stats.md: %v\n"+
140 + "All output metrics: %v\n"+
141 + "Documented metrics: %v",
142 + undocumentedMetrics, outputMetrics, documentedMetrics)
143 +}
144 +
145 +// TestProvideStatBasic tests basic functionality of ipfs provide stat
146 +func TestProvideStatBasic(t *testing.T) {
147 + t.Parallel()
148 +
149 + t.Run("works with Sweep provider and shows brief output", func(t *testing.T) {
150 + t.Parallel()
151 +
152 + h := harness.NewT(t)
153 + node := h.NewNode().Init()
154 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", true)
155 + node.SetIPFSConfig("Provide.Enabled", true)
156 + node.StartDaemon()
157 + defer node.StopDaemon()
158 +
159 + res := node.IPFS("provide", "stat")
160 + require.NoError(t, res.Err)
161 + assert.Empty(t, res.Stderr.String())
162 +
163 + output := res.Stdout.String()
164 + // Brief output should contain specific full labels
165 + assert.Contains(t, output, "Provide queue:")
166 + assert.Contains(t, output, "Reprovide queue:")
167 + assert.Contains(t, output, "CIDs scheduled:")
168 + assert.Contains(t, output, "Regions scheduled:")
169 + assert.Contains(t, output, "Avg record holders:")
170 + assert.Contains(t, output, "Ongoing provides:")
171 + assert.Contains(t, output, "Ongoing reprovides:")
172 + assert.Contains(t, output, "Total CIDs provided:")
173 + })
174 +
175 + t.Run("requires daemon to be online", func(t *testing.T) {
176 + t.Parallel()
177 +
178 + h := harness.NewT(t)
179 + node := h.NewNode().Init()
180 +
181 + res := node.RunIPFS("provide", "stat")
182 + assert.Error(t, res.Err)
183 + assert.Contains(t, res.Stderr.String(), "this command must be run in online mode")
184 + })
185 +}
186 +
187 +// TestProvideStatFlags tests various command flags
188 +func TestProvideStatFlags(t *testing.T) {
189 + t.Parallel()
190 +
191 + t.Run("--all flag shows all sections with headings", func(t *testing.T) {
192 + t.Parallel()
193 +
194 + h := harness.NewT(t)
195 + node := h.NewNode().Init()
196 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", true)
197 + node.SetIPFSConfig("Provide.Enabled", true)
198 + node.StartDaemon()
199 + defer node.StopDaemon()
200 +
201 + res := node.IPFS("provide", "stat", "--all")
202 + require.NoError(t, res.Err)
203 +
204 + output := res.Stdout.String()
205 + // Should contain section headings with colons
206 + assert.Contains(t, output, "Connectivity:")
207 + assert.Contains(t, output, "Queues:")
208 + assert.Contains(t, output, "Schedule:")
209 + assert.Contains(t, output, "Timings:")
210 + assert.Contains(t, output, "Network:")
211 + assert.Contains(t, output, "Operations:")
212 + assert.Contains(t, output, "Workers:")
213 +
214 + // Should contain detailed metrics not in brief mode
215 + assert.Contains(t, output, "Uptime:")
216 + assert.Contains(t, output, "Cycle started:")
217 + assert.Contains(t, output, "Reprovide interval:")
218 + assert.Contains(t, output, "Peers swept:")
219 + assert.Contains(t, output, "Full keyspace coverage:")
220 + })
221 +
222 + t.Run("--compact requires --all", func(t *testing.T) {
223 + t.Parallel()
224 +
225 + h := harness.NewT(t)
226 + node := h.NewNode().Init()
227 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", true)
228 + node.SetIPFSConfig("Provide.Enabled", true)
229 + node.StartDaemon()
230 + defer node.StopDaemon()
231 +
232 + res := node.RunIPFS("provide", "stat", "--compact")
233 + assert.Error(t, res.Err)
234 + assert.Contains(t, res.Stderr.String(), "--compact requires --all flag")
235 + })
236 +
237 + t.Run("--compact with --all shows 2-column layout", func(t *testing.T) {
238 + t.Parallel()
239 +
240 + h := harness.NewT(t)
241 + node := h.NewNode().Init()
242 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", true)
243 + node.SetIPFSConfig("Provide.Enabled", true)
244 + node.StartDaemon()
245 + defer node.StopDaemon()
246 +
247 + res := node.IPFS("provide", "stat", "--all", "--compact")
248 + require.NoError(t, res.Err)
249 +
250 + output := res.Stdout.String()
251 + lines := strings.Split(strings.TrimSpace(output), "\n")
252 + require.NotEmpty(t, lines)
253 +
254 + // In compact mode, find a line that has both Schedule and Connectivity metrics
255 + // This confirms 2-column layout is working
256 + foundTwoColumns := false
257 + for _, line := range lines {
258 + if strings.Contains(line, "CIDs scheduled:") && strings.Contains(line, "Status:") {
259 + foundTwoColumns = true
260 + break
261 + }
262 + }
263 + assert.True(t, foundTwoColumns, "Should have at least one line with both 'CIDs scheduled:' and 'Status:' confirming 2-column layout")
264 + })
265 +
266 + t.Run("individual section flags work with full labels", func(t *testing.T) {
267 + t.Parallel()
268 +
269 + h := harness.NewT(t)
270 + node := h.NewNode().Init()
271 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", true)
272 + node.SetIPFSConfig("Provide.Enabled", true)
273 + node.StartDaemon()
274 + defer node.StopDaemon()
275 +
276 + testCases := []struct {
277 + flag string
278 + contains []string
279 + }{
280 + {
281 + flag: "--connectivity",
282 + contains: []string{"Status:"},
283 + },
284 + {
285 + flag: "--queues",
286 + contains: []string{"Provide queue:", "Reprovide queue:"},
287 + },
288 + {
289 + flag: "--schedule",
290 + contains: []string{"CIDs scheduled:", "Regions scheduled:", "Avg prefix length:", "Next region prefix:", "Next region reprovide:"},
291 + },
292 + {
293 + flag: "--timings",
294 + contains: []string{"Uptime:", "Current time offset:", "Cycle started:", "Reprovide interval:"},
295 + },
296 + {
297 + flag: "--network",
298 + contains: []string{"Avg record holders:", "Peers swept:", "Full keyspace coverage:", "Reachable peers:", "Avg region size:", "Replication factor:"},
299 + },
300 + {
301 + flag: "--operations",
302 + contains: []string{"Ongoing provides:", "Ongoing reprovides:", "Total CIDs provided:", "Total records provided:", "Total provide errors:"},
303 + },
304 + {
305 + flag: "--workers",
306 + contains: []string{"Active workers:", "Free workers:", "Workers stats:", "Periodic", "Burst"},
307 + },
308 + }
309 +
310 + for _, tc := range testCases {
311 + res := node.IPFS("provide", "stat", tc.flag)
312 + require.NoError(t, res.Err, "flag %s should work", tc.flag)
313 + output := res.Stdout.String()
314 + for _, expected := range tc.contains {
315 + assert.Contains(t, output, expected, "flag %s should contain '%s'", tc.flag, expected)
316 + }
317 + }
318 + })
319 +
320 + t.Run("multiple section flags can be combined", func(t *testing.T) {
321 + t.Parallel()
322 +
323 + h := harness.NewT(t)
324 + node := h.NewNode().Init()
325 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", true)
326 + node.SetIPFSConfig("Provide.Enabled", true)
327 + node.StartDaemon()
328 + defer node.StopDaemon()
329 +
330 + res := node.IPFS("provide", "stat", "--network", "--operations")
331 + require.NoError(t, res.Err)
332 +
333 + output := res.Stdout.String()
334 + // Should have section headings when multiple flags combined
335 + assert.Contains(t, output, "Network:")
336 + assert.Contains(t, output, "Operations:")
337 + assert.Contains(t, output, "Avg record holders:")
338 + assert.Contains(t, output, "Ongoing provides:")
339 + })
340 +}
341 +
342 +// TestProvideStatLegacyProvider tests Legacy provider specific behavior
343 +func TestProvideStatLegacyProvider(t *testing.T) {
344 + t.Parallel()
345 +
346 + h := harness.NewT(t)
347 + node := h.NewNode().Init()
348 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", false)
349 + node.SetIPFSConfig("Provide.Enabled", true)
350 + node.StartDaemon()
351 + defer node.StopDaemon()
352 +
353 + t.Run("shows legacy stats from old provider system", func(t *testing.T) {
354 + res := node.IPFS("provide", "stat")
355 + require.NoError(t, res.Err)
356 +
357 + // Legacy provider shows stats from the old reprovider system
358 + output := res.Stdout.String()
359 + assert.Contains(t, output, "TotalReprovides:")
360 + assert.Contains(t, output, "AvgReprovideDuration:")
361 + assert.Contains(t, output, "LastReprovideDuration:")
362 + })
363 +
364 + t.Run("rejects flags with legacy provider", func(t *testing.T) {
365 + flags := []string{"--all", "--connectivity", "--queues", "--network", "--workers"}
366 + for _, flag := range flags {
367 + res := node.RunIPFS("provide", "stat", flag)
368 + assert.Error(t, res.Err, "flag %s should be rejected for legacy provider", flag)
369 + assert.Contains(t, res.Stderr.String(), "cannot use flags with legacy provide stats")
370 + }
371 + })
372 +
373 + t.Run("rejects --lan flag with legacy provider", func(t *testing.T) {
374 + res := node.RunIPFS("provide", "stat", "--lan")
375 + assert.Error(t, res.Err)
376 + assert.Contains(t, res.Stderr.String(), "LAN stats only available for Sweep provider with Dual DHT")
377 + })
378 +}
379 +
380 +// TestProvideStatOutputFormats tests different output formats
381 +func TestProvideStatOutputFormats(t *testing.T) {
382 + t.Parallel()
383 +
384 + t.Run("JSON output with Sweep provider", func(t *testing.T) {
385 + t.Parallel()
386 +
387 + h := harness.NewT(t)
388 + node := h.NewNode().Init()
389 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", true)
390 + node.SetIPFSConfig("Provide.Enabled", true)
391 + node.StartDaemon()
392 + defer node.StopDaemon()
393 +
394 + res := node.IPFS("provide", "stat", "--enc=json")
395 + require.NoError(t, res.Err)
396 +
397 + // Parse JSON to verify structure
398 + var result struct {
399 + Sweep map[string]interface{} `json:"Sweep"`
400 + Legacy map[string]interface{} `json:"Legacy"`
401 + }
402 + err := json.Unmarshal([]byte(res.Stdout.String()), &result)
403 + require.NoError(t, err, "Output should be valid JSON")
404 + assert.NotNil(t, result.Sweep, "Sweep stats should be present")
405 + assert.Nil(t, result.Legacy, "Legacy stats should not be present")
406 + })
407 +
408 + t.Run("JSON output with Legacy provider", func(t *testing.T) {
409 + t.Parallel()
410 +
411 + h := harness.NewT(t)
412 + node := h.NewNode().Init()
413 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", false)
414 + node.SetIPFSConfig("Provide.Enabled", true)
415 + node.StartDaemon()
416 + defer node.StopDaemon()
417 +
418 + res := node.IPFS("provide", "stat", "--enc=json")
419 + require.NoError(t, res.Err)
420 +
421 + // Parse JSON to verify structure
422 + var result struct {
423 + Sweep map[string]interface{} `json:"Sweep"`
424 + Legacy map[string]interface{} `json:"Legacy"`
425 + }
426 + err := json.Unmarshal([]byte(res.Stdout.String()), &result)
427 + require.NoError(t, err, "Output should be valid JSON")
428 + assert.Nil(t, result.Sweep, "Sweep stats should not be present")
429 + assert.NotNil(t, result.Legacy, "Legacy stats should be present")
430 + })
431 +}
432 +
433 +// TestProvideStatIntegration tests integration with provide operations
434 +func TestProvideStatIntegration(t *testing.T) {
435 + t.Parallel()
436 +
437 + t.Run("stats reflect content being added to schedule", func(t *testing.T) {
438 + t.Parallel()
439 +
440 + h := harness.NewT(t)
441 + node := h.NewNode().Init()
442 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", true)
443 + node.SetIPFSConfig("Provide.Enabled", true)
444 + node.SetIPFSConfig("Provide.DHT.Interval", "1h")
445 + node.StartDaemon()
446 + defer node.StopDaemon()
447 +
448 + // Get initial scheduled CID count
449 + res1 := node.IPFS("provide", "stat", "--enc=json")
450 + require.NoError(t, res1.Err)
451 + initialKeys := parseSweepStats(t, res1.Stdout.String()).Sweep.Schedule.Keys
452 +
453 + // Add content - this should increase CIDs scheduled
454 + node.IPFSAddStr("test content for stats")
455 +
456 + // Wait for content to appear in schedule (with timeout)
457 + // The buffered provider may take a moment to schedule items
458 + require.Eventually(t, func() bool {
459 + res := node.IPFS("provide", "stat", "--enc=json")
460 + require.NoError(t, res.Err)
461 + stats := parseSweepStats(t, res.Stdout.String())
462 + return stats.Sweep.Schedule.Keys > initialKeys
463 + }, provideStatEventuallyTimeout, provideStatEventuallyTick, "Content should appear in schedule after adding")
464 + })
465 +
466 + t.Run("stats work with all documented strategies", func(t *testing.T) {
467 + t.Parallel()
468 +
469 + // Test all strategies documented in docs/config.md#providestrategy
470 + strategies := []string{"all", "pinned", "roots", "mfs", "pinned+mfs"}
471 + for _, strategy := range strategies {
472 + h := harness.NewT(t)
473 + node := h.NewNode().Init()
474 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", true)
475 + node.SetIPFSConfig("Provide.Enabled", true)
476 + node.SetIPFSConfig("Provide.Strategy", strategy)
477 + node.StartDaemon()
478 +
479 + res := node.IPFS("provide", "stat")
480 + require.NoError(t, res.Err, "stats should work with strategy %s", strategy)
481 + output := res.Stdout.String()
482 + assert.NotEmpty(t, output)
483 + assert.Contains(t, output, "CIDs scheduled:")
484 +
485 + node.StopDaemon()
486 + }
487 + })
488 +}
489 +
490 +// TestProvideStatDisabledConfig tests behavior when provide system is disabled
491 +func TestProvideStatDisabledConfig(t *testing.T) {
492 + t.Parallel()
493 +
494 + t.Run("Provide.Enabled=false returns error stats not available", func(t *testing.T) {
495 + t.Parallel()
496 +
497 + h := harness.NewT(t)
498 + node := h.NewNode().Init()
499 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", true)
500 + node.SetIPFSConfig("Provide.Enabled", false)
501 + node.StartDaemon()
502 + defer node.StopDaemon()
503 +
504 + res := node.RunIPFS("provide", "stat")
505 + assert.Error(t, res.Err)
506 + assert.Contains(t, res.Stderr.String(), "stats not available")
507 + })
508 +
509 + t.Run("Provide.Enabled=true with Provide.DHT.Interval=0 returns error stats not available", func(t *testing.T) {
510 + t.Parallel()
511 +
512 + h := harness.NewT(t)
513 + node := h.NewNode().Init()
514 + node.SetIPFSConfig("Provide.DHT.SweepEnabled", true)
515 + node.SetIPFSConfig("Provide.Enabled", true)
516 + node.SetIPFSConfig("Provide.DHT.Interval", "0")
517 + node.StartDaemon()
518 + defer node.StopDaemon()
519 +
520 + res := node.RunIPFS("provide", "stat")
521 + assert.Error(t, res.Err)
522 + assert.Contains(t, res.Stderr.String(), "stats not available")
523 + })
524 +}
test/dependencies/go.mod
+19 -16
@@ -136,7 +136,7 @@ require (
136 github.com/huin/goupnp v1.3.0 // indirect
137 github.com/inconshreveable/mousetrap v1.1.0 // indirect
138 github.com/ipfs/bbloom v0.0.4 // indirect
139 - github.com/ipfs/boxo v0.35.1-0.20251016232905-37006871a40e // indirect
139 + github.com/ipfs/boxo v0.35.0 // indirect
140 github.com/ipfs/go-bitfield v1.1.0 // indirect
141 github.com/ipfs/go-block-format v0.2.3 // indirect
142 github.com/ipfs/go-cid v0.5.0 // indirect
@@ -150,7 +150,7 @@ require (
150 github.com/ipfs/go-metrics-interface v0.3.0 // indirect
151 github.com/ipfs/go-unixfsnode v1.10.2 // indirect
152 github.com/ipfs/kubo v0.31.0 // indirect
153 - github.com/ipld/go-car/v2 v2.16.0 // indirect
153 + github.com/ipld/go-car/v2 v2.15.0 // indirect
154 github.com/ipld/go-codec-dagpb v1.7.0 // indirect
155 github.com/ipld/go-ipld-prime v0.21.0 // indirect
156 github.com/ipshipyard/p2p-forge v0.6.1 // indirect
@@ -182,14 +182,14 @@ require (
182 github.com/libp2p/go-cidranger v1.1.0 // indirect
183 github.com/libp2p/go-doh-resolver v0.5.0 // indirect
184 github.com/libp2p/go-flow-metrics v0.3.0 // indirect
185 - github.com/libp2p/go-libp2p v0.44.0 // indirect
185 + github.com/libp2p/go-libp2p v0.43.0 // indirect
186 github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect
187 - github.com/libp2p/go-libp2p-kad-dht v0.35.1 // indirect
187 + github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251017193437-abd04263daac // indirect
188 github.com/libp2p/go-libp2p-kbucket v0.8.0 // indirect
189 github.com/libp2p/go-libp2p-record v0.3.1 // indirect
190 github.com/libp2p/go-libp2p-routing-helpers v0.7.5 // indirect
191 github.com/libp2p/go-msgio v0.3.0 // indirect
192 - github.com/libp2p/go-netroute v0.3.0 // indirect
192 + github.com/libp2p/go-netroute v0.2.2 // indirect
193 github.com/libp2p/go-reuseport v0.4.0 // indirect
194 github.com/macabu/inamedparam v0.1.3 // indirect
195 github.com/magiconair/properties v1.8.7 // indirect
@@ -214,7 +214,7 @@ require (
214 github.com/multiformats/go-multiaddr-dns v0.4.1 // indirect
215 github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
216 github.com/multiformats/go-multibase v0.2.0 // indirect
217 - github.com/multiformats/go-multicodec v0.10.0 // indirect
217 + github.com/multiformats/go-multicodec v0.9.2 // indirect
218 github.com/multiformats/go-multistream v0.6.1 // indirect
219 github.com/multiformats/go-varint v0.1.0 // indirect
220 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
@@ -258,7 +258,9 @@ require (
258 github.com/quasilyte/gogrep v0.5.0 // indirect
259 github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect
260 github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
261 - github.com/quic-go/quic-go v0.55.0 // indirect
261 + github.com/quic-go/qpack v0.5.1 // indirect
262 + github.com/quic-go/quic-go v0.54.1 // indirect
263 + github.com/quic-go/webtransport-go v0.9.0 // indirect
264 github.com/raeperd/recvcheck v0.2.0 // indirect
265 github.com/rivo/uniseg v0.4.7 // indirect
266 github.com/rogpeppe/go-internal v1.14.1 // indirect
@@ -323,24 +325,25 @@ require (
325 go.uber.org/automaxprocs v1.6.0 // indirect
326 go.uber.org/dig v1.19.0 // indirect
327 go.uber.org/fx v1.24.0 // indirect
328 + go.uber.org/mock v0.5.2 // indirect
329 go.uber.org/multierr v1.11.0 // indirect
330 go.uber.org/zap v1.27.0 // indirect
331 go.uber.org/zap/exp v0.3.0 // indirect
332 go.yaml.in/yaml/v2 v2.4.3 // indirect
330 - golang.org/x/crypto v0.43.0 // indirect
331 - golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b // indirect
333 + golang.org/x/crypto v0.42.0 // indirect
334 + golang.org/x/exp v0.0.0-20250911091902-df9299821621 // indirect
335 golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect
333 - golang.org/x/mod v0.29.0 // indirect
334 - golang.org/x/net v0.46.0 // indirect
336 + golang.org/x/mod v0.28.0 // indirect
337 + golang.org/x/net v0.44.0 // indirect
338 golang.org/x/sync v0.17.0 // indirect
336 - golang.org/x/sys v0.37.0 // indirect
337 - golang.org/x/term v0.36.0 // indirect
338 - golang.org/x/text v0.30.0 // indirect
339 + golang.org/x/sys v0.36.0 // indirect
340 + golang.org/x/term v0.35.0 // indirect
341 + golang.org/x/text v0.29.0 // indirect
342 golang.org/x/time v0.12.0 // indirect
340 - golang.org/x/tools v0.38.0 // indirect
343 + golang.org/x/tools v0.37.0 // indirect
344 golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da // indirect
345 gonum.org/v1/gonum v0.16.0 // indirect
343 - google.golang.org/protobuf v1.36.10 // indirect
346 + google.golang.org/protobuf v1.36.9 // indirect
347 gopkg.in/ini.v1 v1.67.0 // indirect
348 gopkg.in/yaml.v2 v2.4.0 // indirect
349 gopkg.in/yaml.v3 v3.0.1 // indirect
test/dependencies/go.sum
+46 -38
@@ -334,8 +334,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
334 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
335 github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
336 github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
337 -github.com/ipfs/boxo v0.35.1-0.20251016232905-37006871a40e h1:GF4HRwPWeXWJQLjkAVmN54ftHDCZ+ScP9ievuxtbx9s=
338 -github.com/ipfs/boxo v0.35.1-0.20251016232905-37006871a40e/go.mod h1:S5kJHjrzXoLDhjFVPVulE9IQnRzex9yGnG+otzF/HZg=
337 +github.com/ipfs/boxo v0.35.0 h1:3Mku5arSbAZz0dvb4goXRsQuZkFkPrGr5yYdu0YM1pY=
338 +github.com/ipfs/boxo v0.35.0/go.mod h1:uhaF0DGnbgEiXDTmD249jCGbxVkMm6+Ew85q6Uub7lo=
339 github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
340 github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
341 github.com/ipfs/go-block-format v0.2.3 h1:mpCuDaNXJ4wrBJLrtEaGFGXkferrw5eqVvzaHhtFKQk=
@@ -350,10 +350,14 @@ github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ
350 github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
351 github.com/ipfs/go-dsqueue v0.1.0 h1:OrahKDtT/Q+iMgKaM9XWdxrYPVASFpTuLah8QpKjboc=
352 github.com/ipfs/go-dsqueue v0.1.0/go.mod h1:iLNkodSOSKTLn0gCvL9ikArz5rZfNh8F9/BRvHe7RbY=
353 +github.com/ipfs/go-ipfs-blockstore v1.3.1 h1:cEI9ci7V0sRNivqaOr0elDsamxXFxJMMMy7PTTDQNsQ=
354 +github.com/ipfs/go-ipfs-blockstore v1.3.1/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE=
355 github.com/ipfs/go-ipfs-cmds v0.15.0 h1:nQDgKadrzyiFyYoZMARMIoVoSwe3gGTAfGvrWLeAQbQ=
356 github.com/ipfs/go-ipfs-cmds v0.15.0/go.mod h1:VABf/mv/wqvYX6hLG6Z+40eNAEw3FQO0bSm370Or3Wk=
357 github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ=
358 github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw=
359 +github.com/ipfs/go-ipfs-ds-help v1.1.1 h1:B5UJOH52IbcfS56+Ul+sv8jnIV10lbjLF5eOO0C66Nw=
360 +github.com/ipfs/go-ipfs-ds-help v1.1.1/go.mod h1:75vrVCkSdSFidJscs8n4W+77AtTpCIAdDGAwjitJMIo=
361 github.com/ipfs/go-ipfs-pq v0.0.3 h1:YpoHVJB+jzK15mr/xsWC574tyDLkezVrDNeaalQBsTE=
362 github.com/ipfs/go-ipfs-pq v0.0.3/go.mod h1:btNw5hsHBpRcSSgZtiNm/SLj5gYIZ18AKtv3kERkRb4=
363 github.com/ipfs/go-ipfs-redirects-file v0.1.2 h1:QCK7VtL91FH17KROVVy5KrzDx2hu68QvB2FTWk08ZQk=
@@ -364,6 +368,8 @@ github.com/ipfs/go-ipld-format v0.6.3 h1:9/lurLDTotJpZSuL++gh3sTdmcFhVkCwsgx2+rA
368 github.com/ipfs/go-ipld-format v0.6.3/go.mod h1:74ilVN12NXVMIV+SrBAyC05UJRk0jVvGqdmrcYZvCBk=
369 github.com/ipfs/go-ipld-legacy v0.2.2 h1:DThbqCPVLpWBcGtU23KDLiY2YRZZnTkXQyfz8aOfBkQ=
370 github.com/ipfs/go-ipld-legacy v0.2.2/go.mod h1:hhkj+b3kG9b2BcUNw8IFYAsfeNo8E3U7eYlWeAOPyDU=
371 +github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8=
372 +github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo=
373 github.com/ipfs/go-log/v2 v2.8.2 h1:nVG4nNHUwwI/sTs9Bi5iE8sXFQwXs3AjkkuWhg7+Y2I=
374 github.com/ipfs/go-log/v2 v2.8.2/go.mod h1:UhIYAwMV7Nb4ZmihUxfIRM2Istw/y9cAk3xaK+4Zs2c=
375 github.com/ipfs/go-metrics-interface v0.3.0 h1:YwG7/Cy4R94mYDUuwsBfeziJCVm9pBMJ6q/JR9V40TU=
@@ -380,14 +386,14 @@ github.com/ipfs/iptb v1.4.1 h1:faXd3TKGPswbHyZecqqg6UfbES7RDjTKQb+6VFPKDUo=
386 github.com/ipfs/iptb v1.4.1/go.mod h1:nTsBMtVYFEu0FjC5DgrErnABm3OG9ruXkFXGJoTV5OA=
387 github.com/ipfs/iptb-plugins v0.5.1 h1:11PNTNEt2+SFxjUcO5qpyCTXqDj6T8Tx9pU/G4ytCIQ=
388 github.com/ipfs/iptb-plugins v0.5.1/go.mod h1:mscJAjRnu4g16QK6oUBn9RGpcp8ueJmLfmPxIG/At78=
383 -github.com/ipld/go-car/v2 v2.16.0 h1:LWe0vmN/QcQmUU4tr34W5Nv5mNraW+G6jfN2s+ndBco=
384 -github.com/ipld/go-car/v2 v2.16.0/go.mod h1:RqFGWN9ifcXVmCrTAVnfnxiWZk1+jIx67SYhenlmL34=
389 +github.com/ipld/go-car/v2 v2.15.0 h1:RxtZcGXFx72zFESl+UUsCNQV2YMcy3gEMYx9M3uio24=
390 +github.com/ipld/go-car/v2 v2.15.0/go.mod h1:ovlq/n3xlVJDmoiN3Kd/Z7kIzQbdTIFSwltfOP+qIgk=
391 github.com/ipld/go-codec-dagpb v1.7.0 h1:hpuvQjCSVSLnTnHXn+QAMR0mLmb1gA6wl10LExo2Ts0=
392 github.com/ipld/go-codec-dagpb v1.7.0/go.mod h1:rD3Zg+zub9ZnxcLwfol/OTQRVjaLzXypgy4UqHQvilM=
393 github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E=
394 github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ=
389 -github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20250821084354-a425e60cd714 h1:cqNk8PEwHnK0vqWln+U/YZhQc9h2NB3KjUjDPZo5Q2s=
390 -github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20250821084354-a425e60cd714/go.mod h1:ZEUdra3CoqRVRYgAX/jAJO9aZGz6SKtKEG628fHHktY=
395 +github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd h1:gMlw/MhNr2Wtp5RwGdsW23cs+yCuj9k2ON7i9MiJlRo=
396 +github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd/go.mod h1:wZ8hH8UxeryOs4kJEJaiui/s00hDSbE37OKsL47g+Sw=
397 github.com/ipshipyard/p2p-forge v0.6.1 h1:987/hUC1YxI56CcMX6iTB+9BLjFV0d2SJnig9Z1pf8A=
398 github.com/ipshipyard/p2p-forge v0.6.1/go.mod h1:pj8Zcs+ex5OMq5a1bFLHqW0oL3qYO0v5eGLZmit0l7U=
399 github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
@@ -458,12 +464,12 @@ github.com/libp2p/go-doh-resolver v0.5.0 h1:4h7plVVW+XTS+oUBw2+8KfoM1jF6w8XmO7+s
464 github.com/libp2p/go-doh-resolver v0.5.0/go.mod h1:aPDxfiD2hNURgd13+hfo29z9IC22fv30ee5iM31RzxU=
465 github.com/libp2p/go-flow-metrics v0.3.0 h1:q31zcHUvHnwDO0SHaukewPYgwOBSxtt830uJtUx6784=
466 github.com/libp2p/go-flow-metrics v0.3.0/go.mod h1:nuhlreIwEguM1IvHAew3ij7A8BMlyHQJ279ao24eZZo=
461 -github.com/libp2p/go-libp2p v0.44.0 h1:5Gtt8OrF8yiXmH+Mx4+/iBeFRMK1TY3a8OrEBDEqAvs=
462 -github.com/libp2p/go-libp2p v0.44.0/go.mod h1:NovCojezAt4dnDd4fH048K7PKEqH0UFYYqJRjIIu8zc=
467 +github.com/libp2p/go-libp2p v0.43.0 h1:b2bg2cRNmY4HpLK8VHYQXLX2d3iND95OjodLFymvqXU=
468 +github.com/libp2p/go-libp2p v0.43.0/go.mod h1:IiSqAXDyP2sWH+J2gs43pNmB/y4FOi2XQPbsb+8qvzc=
469 github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94=
470 github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8=
465 -github.com/libp2p/go-libp2p-kad-dht v0.35.1 h1:RQglhc9OxqDwlFFdhQMwKxIPBIBfGsleROnK5hqVsoE=
466 -github.com/libp2p/go-libp2p-kad-dht v0.35.1/go.mod h1:1oCXzkkBiYh3d5cMWLpInSOZ6am2AlpC4G+GDcZFcE0=
471 +github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251017193437-abd04263daac h1:2TWHkp8MJBLfwIRMUfvjFb2DABcjLaYAwVBzAEirkhU=
472 +github.com/libp2p/go-libp2p-kad-dht v0.35.2-0.20251017193437-abd04263daac/go.mod h1:aHMTg23iseX9grGSfA5gFUzLrqzmYbA8PqgGPqM8VkI=
473 github.com/libp2p/go-libp2p-kbucket v0.8.0 h1:QAK7RzKJpYe+EuSEATAaaHYMYLkPDGC18m9jxPLnU8s=
474 github.com/libp2p/go-libp2p-kbucket v0.8.0/go.mod h1:JMlxqcEyKwO6ox716eyC0hmiduSWZZl6JY93mGaaqc4=
475 github.com/libp2p/go-libp2p-record v0.3.1 h1:cly48Xi5GjNw5Wq+7gmjfBiG9HCzQVkiZOUZ8kUl+Fg=
@@ -474,8 +480,8 @@ github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUI
480 github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg=
481 github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0=
482 github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM=
477 -github.com/libp2p/go-netroute v0.3.0 h1:nqPCXHmeNmgTJnktosJ/sIef9hvwYCrsLxXmfNks/oc=
478 -github.com/libp2p/go-netroute v0.3.0/go.mod h1:Nkd5ShYgSMS5MUKy/MU2T57xFoOKvvLR92Lic48LEyA=
483 +github.com/libp2p/go-netroute v0.2.2 h1:Dejd8cQ47Qx2kRABg6lPwknU7+nBnFRpko45/fFPuZ8=
484 +github.com/libp2p/go-netroute v0.2.2/go.mod h1:Rntq6jUAH0l9Gg17w5bFGhcC9a+vk4KNXs6s7IljKYE=
485 github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s=
486 github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU=
487 github.com/libp2p/go-yamux/v5 v5.0.1 h1:f0WoX/bEF2E8SbE4c/k1Mo+/9z0O4oC/hWEA+nfYRSg=
@@ -490,8 +496,6 @@ github.com/maratori/testableexamples v1.0.0 h1:dU5alXRrD8WKSjOUnmJZuzdxWOEQ57+7s
496 github.com/maratori/testableexamples v1.0.0/go.mod h1:4rhjL1n20TUTT4vdh3RDqSizKLyXp7K2u6HgraZCGzE=
497 github.com/maratori/testpackage v1.1.1 h1:S58XVV5AD7HADMmD0fNnziNHqKvSdDuEKdPD1rNTU04=
498 github.com/maratori/testpackage v1.1.1/go.mod h1:s4gRK/ym6AMrqpOa/kEbQTV4Q4jb7WeLZzVhVVVOQMc=
493 -github.com/marcopolo/simnet v0.0.1 h1:rSMslhPz6q9IvJeFWDoMGxMIrlsbXau3NkuIXHGJxfg=
494 -github.com/marcopolo/simnet v0.0.1/go.mod h1:WDaQkgLAjqDUEBAOXz22+1j6wXKfGlC5sD5XWt3ddOs=
499 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
500 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
501 github.com/matoous/godox v1.1.0 h1:W5mqwbyWrwZv6OQ5Z1a/DHGMOvXYCBP3+Ht7KMoJhq4=
@@ -549,8 +553,8 @@ github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/e
553 github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo=
554 github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g=
555 github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk=
552 -github.com/multiformats/go-multicodec v0.10.0 h1:UpP223cig/Cx8J76jWt91njpK3GTAO1w02sdcjZDSuc=
553 -github.com/multiformats/go-multicodec v0.10.0/go.mod h1:wg88pM+s2kZJEQfRCKBNU+g32F5aWBEjyFHXvZLTcLI=
556 +github.com/multiformats/go-multicodec v0.9.2 h1:YrlXCuqxjqm3bXl+vBq5LKz5pz4mvAsugdqy78k0pXQ=
557 +github.com/multiformats/go-multicodec v0.9.2/go.mod h1:LLWNMtyV5ithSBUo3vFIMaeDy+h3EbkMTek1m+Fybbo=
558 github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
559 github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U=
560 github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM=
@@ -577,6 +581,8 @@ github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus
581 github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
582 github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU=
583 github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
584 +github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
585 +github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
586 github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
587 github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
588 github.com/otiai10/copy v1.14.0 h1:dCI/t1iTdYGtkvCuBG2BgR6KZa83PTclw4U5n2wAllU=
@@ -672,8 +678,8 @@ github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4l
678 github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ=
679 github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
680 github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
675 -github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
676 -github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
681 +github.com/quic-go/quic-go v0.54.1 h1:4ZAWm0AhCb6+hE+l5Q1NAL0iRn/ZrMwqHRGQiFwj2eg=
682 +github.com/quic-go/quic-go v0.54.1/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
683 github.com/quic-go/webtransport-go v0.9.0 h1:jgys+7/wm6JarGDrW+lD/r9BGqBAmqY/ssklE09bA70=
684 github.com/quic-go/webtransport-go v0.9.0/go.mod h1:4FUYIiUc75XSsF6HShcLeXXYZJ9AGwo/xh3L8M/P1ao=
685 github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI=
@@ -877,6 +883,8 @@ go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6
883 go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
884 go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
885 go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
886 +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
887 +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
888 go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
889 go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
890 go.uber.org/dig v1.19.0 h1:BACLhebsYdpQ7IROQ1AGPjrXcP5dF80U3gKoFzbaq/4=
@@ -911,11 +919,11 @@ golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98y
919 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
920 golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
921 golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
914 -golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
915 -golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
922 +golang.org/x/crypto v0.42.0 h1:chiH31gIWm57EkTXpwnqf8qeuMUi0yekh6mT2AvFlqI=
923 +golang.org/x/crypto v0.42.0/go.mod h1:4+rDnOTJhQCx2q7/j6rAN5XDw8kPjeaXEUR2eL94ix8=
924 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
917 -golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b h1:18qgiDvlvH7kk8Ioa8Ov+K6xCi0GMvmGfGW0sgd/SYA=
918 -golang.org/x/exp v0.0.0-20251009144603-d2f985daa21b/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70=
925 +golang.org/x/exp v0.0.0-20250911091902-df9299821621 h1:2id6c1/gto0kaHYyrixvknJ8tUK/Qs5IsmBtrc+FtgU=
926 +golang.org/x/exp v0.0.0-20250911091902-df9299821621/go.mod h1:TwQYMMnGpvZyc+JpB/UAuTNIsVJifOlSkrZkhcvpVUk=
927 golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
928 golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
929 golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac h1:TSSpLIG4v+p0rPv1pNOQtl1I8knsO4S9trOxNMOLVP4=
@@ -936,8 +944,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
944 golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
945 golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
946 golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
939 -golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
940 -golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
947 +golang.org/x/mod v0.28.0 h1:gQBtGhjxykdjY9YhZpSlZIsbnaE2+PgjfLWUQTnoZ1U=
948 +golang.org/x/mod v0.28.0/go.mod h1:yfB/L0NOf/kmEbXjzCPOx1iK1fRutOydrCMsqRhEBxI=
949 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
950 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
951 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -965,8 +973,8 @@ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
973 golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
974 golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
975 golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
968 -golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
969 -golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
976 +golang.org/x/net v0.44.0 h1:evd8IRDyfNBMBTTY5XRF1vaZlD+EmWx6x8PkhR04H/I=
977 +golang.org/x/net v0.44.0/go.mod h1:ECOoLqd5U3Lhyeyo/QDCEVQ4sNgYsqvCZ722XogGieY=
978 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
979 golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
980 golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@@ -1016,10 +1024,10 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1024 golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1025 golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1026 golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
1019 -golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
1020 -golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
1021 -golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=
1022 -golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
1027 +golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
1028 +golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
1029 +golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053 h1:dHQOQddU4YHS5gY33/6klKjq7Gp3WwMyOXGNp5nzRj8=
1030 +golang.org/x/telemetry v0.0.0-20250908211612-aef8a434d053/go.mod h1:+nZKN+XVh4LCiA9DV3ywrzN4gumyCnKjau3NGb9SGoE=
1031 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
1032 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
1033 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -1031,8 +1039,8 @@ golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
1039 golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
1040 golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
1041 golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
1034 -golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
1035 -golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
1042 +golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
1043 +golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
1044 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
1045 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
1046 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
@@ -1046,8 +1054,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
1054 golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
1055 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
1056 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
1049 -golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
1050 -golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
1057 +golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
1058 +golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
1059 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
1060 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
1061 golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
@@ -1078,8 +1086,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
1086 golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
1087 golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
1088 golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
1081 -golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
1082 -golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
1089 +golang.org/x/tools v0.37.0 h1:DVSRzp7FwePZW356yEAChSdNcQo6Nsp+fex1SUW09lE=
1090 +golang.org/x/tools v0.37.0/go.mod h1:MBN5QPQtLMHVdvsbtarmTNukZDdgwdwlO5qGacAzF0w=
1091 golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=
1092 golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
1093 golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
@@ -1108,8 +1116,8 @@ google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmE
1116 google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
1117 google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
1118 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
1111 -google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
1112 -google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
1119 +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
1120 +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
1121 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
1122 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
1123 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=