feat!: update to libp2p-v3 (#84)

Updates all deps to the latest versions BREAKING CHANGE: use with libp2p@v3 only

Alex Potsides committed Jan 16, 2026 at 12:10 UTC a92ce3e1b51555657d3465205c9c6b3216bc6ae3
18 files changed +107 -90
.github/dependabot.yml
+3 -4
@@ -1,8 +1,7 @@
1 version: 2
2 updates:
3 - package-ecosystem: npm
4 - directories:
5 - - "/"
4 + directory: "/"
5 schedule:
6 interval: daily
7 time: "10:00"
@@ -11,14 +10,14 @@ updates:
10 prefix: "deps"
11 prefix-development: "chore"
12 groups:
14 - interplanetary-deps: # group all deps that should be updated when Helia deps need updated
13 + interplanetary-deps: # Helia/libp2p deps
14 patterns:
15 - "*helia*"
16 - "*libp2p*"
17 - "*multiformats*"
18 - "*blockstore*"
19 - "*datastore*"
21 - kubo-deps: # group kubo, kubo-rpc-client, and ipfsd-ctl updates
20 + kubo-deps: # kubo deps
21 patterns:
22 - "*kubo*"
23 - "ipfsd-ctl"
.github/workflows/semantic-pull-request.yml
+1 -1
@@ -9,4 +9,4 @@ on:
9
10 jobs:
11 main:
12 - uses: pl-strflt/.github/.github/workflows/reusable-semantic-pull-request.yml@v0.3
12 + uses: ipdxco/unified-github-workflows/.github/workflows/reusable-semantic-pull-request.yml@v1
.github/workflows/stale.yml
+1 -1
@@ -1,4 +1,4 @@
1 -name: Close Stale Issues
1 +name: Close and mark stale issue
2
3 on:
4 schedule:
packages/libp2p-devtools/package.json
+13 -13
@@ -139,25 +139,25 @@
139 "release": "aegir release"
140 },
141 "dependencies": {
142 - "@ipshipyard/libp2p-inspector-metrics": "^1.0.1",
143 - "@ipshipyard/libp2p-inspector-ui": "^1.0.1",
144 - "@libp2p/interface": "^2.10.2",
142 + "@ipshipyard/libp2p-inspector-metrics": "^1.0.0",
143 + "@ipshipyard/libp2p-inspector-ui": "^1.0.0",
144 + "@libp2p/interface": "^3.1.0",
145 "it-pipe": "^3.0.1",
146 "it-pushable": "^3.2.3",
147 - "it-rpc": "^1.1.0",
147 + "it-rpc": "^1.2.1",
148 "it-stream-types": "^2.0.2",
149 - "multiformats": "^13.3.6",
150 - "react": "^19.1.0",
151 - "react-dom": "^19.1.0",
152 - "react-syntax-highlighter": "^15.6.1",
149 + "multiformats": "^13.4.2",
150 + "react": "^19.2.3",
151 + "react-dom": "^19.2.3",
152 + "react-syntax-highlighter": "^16.1.0",
153 "uint8arrays": "^5.1.0"
154 },
155 "devDependencies": {
156 - "@types/chrome": "^0.0.323",
157 - "@types/react": "^19.1.5",
158 - "@types/react-dom": "^19.1.5",
156 + "@types/chrome": "^0.1.33",
157 + "@types/react": "^19.2.8",
158 + "@types/react-dom": "^19.2.3",
159 "@types/react-syntax-highlighter": "^15.5.13",
160 - "aegir": "^47.0.13",
161 - "web-ext": "^8.9.0"
160 + "aegir": "^47.0.25",
161 + "web-ext": "^9.2.0"
162 }
163 }
packages/libp2p-inspector-metrics/package.json
+15 -14
@@ -135,30 +135,31 @@
135 "release": "aegir release"
136 },
137 "dependencies": {
138 - "@libp2p/identify": "^3.0.32",
139 - "@libp2p/interface": "^2.10.2",
140 - "@libp2p/interface-internal": "^2.3.14",
141 - "@libp2p/logger": "^5.1.18",
142 - "@libp2p/peer-id": "^5.1.5",
143 - "@libp2p/ping": "^2.0.32",
144 - "@libp2p/simple-metrics": "^1.3.12",
145 - "@libp2p/utils": "^6.6.5",
146 - "@multiformats/multiaddr": "^12.4.0",
147 - "cborg": "^4.2.11",
138 + "@libp2p/gossipsub": "^15.0.11",
139 + "@libp2p/identify": "^4.0.9",
140 + "@libp2p/interface": "^3.1.0",
141 + "@libp2p/interface-internal": "^3.0.9",
142 + "@libp2p/logger": "^6.2.2",
143 + "@libp2p/peer-id": "^6.0.4",
144 + "@libp2p/ping": "^3.0.9",
145 + "@libp2p/simple-metrics": "^2.0.9",
146 + "@libp2p/utils": "^7.0.9",
147 + "@multiformats/multiaddr": "^13.0.1",
148 + "cborg": "^4.3.2",
149 "dns-packet": "^5.6.1",
150 "it-length-prefixed": "^10.0.1",
151 "it-pipe": "^3.0.1",
152 "it-pushable": "^3.2.3",
152 - "it-rpc": "^1.1.0",
153 + "it-rpc": "^1.2.1",
154 "multicast-dns": "^7.2.5",
154 - "multiformats": "^13.3.6",
155 + "multiformats": "^13.4.2",
156 "progress-events": "^1.0.1",
157 "stream-to-it": "^1.0.1",
158 "uint8arrays": "^5.1.0"
159 },
160 "devDependencies": {
160 - "@libp2p/crypto": "^5.1.4",
161 - "aegir": "^47.0.13",
161 + "@libp2p/crypto": "^5.1.13",
162 + "aegir": "^47.0.25",
163 "sinon-ts": "^2.0.0"
164 },
165 "browser": {
packages/libp2p-inspector-metrics/src/index.ts
+3 -3
@@ -31,7 +31,7 @@ import { getPeers } from './utils/get-peers.js'
31 import { getSelf } from './utils/get-self.js'
32 import type { Messages } from './messages/index.js'
33 import type { InspectorRPC } from './rpc/index.js'
34 -import type { ComponentLogger, Connection, Libp2pEvents, Logger, Metrics, MultiaddrConnection, PeerId, PeerStore, Stream, ContentRouting, PeerRouting, TypedEventTarget, Startable, NodeInfo } from '@libp2p/interface'
34 +import type { ComponentLogger, Libp2pEvents, Logger, Metrics, MultiaddrConnection, PeerId, PeerStore, Stream, ContentRouting, PeerRouting, TypedEventTarget, Startable, NodeInfo } from '@libp2p/interface'
35 import type { TransportManager, Registrar, ConnectionManager, AddressManager } from '@libp2p/interface-internal'
36 import type { Pushable } from 'it-pushable'
37 import type { RPC } from 'it-rpc'
@@ -213,8 +213,8 @@ class InspectorMetrics implements Metrics, Startable {
213 this.simpleMetrics.trackMultiaddrConnection(maConn)
214 }
215
216 - trackProtocolStream (stream: Stream, connection: Connection): void {
217 - this.simpleMetrics.trackProtocolStream(stream, connection)
216 + trackProtocolStream (stream: Stream): void {
217 + this.simpleMetrics.trackProtocolStream(stream)
218 }
219
220 registerMetric (name: any, options: any): any {
packages/libp2p-inspector-metrics/src/messages/messages.ts
+2 -4
@@ -1,7 +1,6 @@
1 import { createServer } from 'node:net'
2 import { start, stop, TypedEventEmitter } from '@libp2p/interface'
3 -import { getThinWaistAddresses } from '@libp2p/utils/get-thin-waist-addresses'
4 -import { isPrivate } from '@libp2p/utils/multiaddr/is-private'
3 +import { getThinWaistAddresses, isPrivate } from '@libp2p/utils'
4 import { multiaddr } from '@multiformats/multiaddr'
5 import { encode, decode } from 'it-length-prefixed'
6 import { pushable } from 'it-pushable'
@@ -99,8 +98,7 @@ class MDNSPortAdvertisement {
98
99 function toMultiaddrs (addr: string | AddressInfo): Multiaddr[] {
100 if (typeof addr === 'string') {
102 - // TODO: wrap with encodeURIComponent https://github.com/multiformats/multiaddr/pull/174
103 - return [multiaddr(`/unix/${addr}`)]
101 + return [multiaddr(`/unix/${encodeURIComponent(addr)}`)]
102 }
103
104 const { family, address, port } = addr
packages/libp2p-inspector-metrics/src/rpc/index.ts
+3 -4
@@ -2,7 +2,7 @@ import { cidCodec } from './codecs/cid.js'
2 import { customProgressEventCodec } from './codecs/custom-progress-event.js'
3 import { multiaddrCodec } from './codecs/multiaddr.js'
4 import { peerIdCodec } from './codecs/peer-id.js'
5 -import type { ContentRouting, PeerId, PeerRouting, AbortOptions, IdentifyResult, Direction, ConnectionTimeline, ConnectionStatus, ConnectionLimits } from '@libp2p/interface'
5 +import type { ContentRouting, PeerId, PeerRouting, AbortOptions, IdentifyResult, ConnectionStatus, ConnectionLimits, MultiaddrConnectionTimeline, MessageStreamDirection } from '@libp2p/interface'
6 import type { OpenConnectionOptions } from '@libp2p/interface-internal'
7 import type { Multiaddr } from '@multiformats/multiaddr'
8 import type { ValueCodec } from 'it-rpc'
@@ -51,9 +51,8 @@ export interface Connection {
51 id: string
52 remoteAddr: Multiaddr
53 remotePeer: PeerId
54 - tags: string[]
55 - direction: Direction
56 - timeline: ConnectionTimeline
54 + direction: MessageStreamDirection
55 + timeline: MultiaddrConnectionTimeline
56 multiplexer?: string
57 encryption?: string
58 status: ConnectionStatus
packages/libp2p-inspector-metrics/src/rpc/rpc.ts
-1
@@ -57,7 +57,6 @@ export function metricsRpc (components: InspectorMetricsComponents): MetricsRPC
57 id: conn.id,
58 remoteAddr: conn.remoteAddr,
59 remotePeer: conn.remotePeer,
60 - tags: conn.tags,
60 direction: conn.direction,
61 timeline: conn.timeline,
62 multiplexer: conn.multiplexer,
packages/libp2p-inspector-metrics/src/utils/get-pubsub.ts
+15 -4
@@ -1,10 +1,21 @@
1 -import { InvalidParametersError, isPubSub } from '@libp2p/interface'
2 -import type { PubSub } from '@libp2p/interface'
1 +import { InvalidParametersError } from '@libp2p/interface'
2 +import type { GossipSub } from '@libp2p/gossipsub'
3
4 -export function getPubSub (component: string, components: any): PubSub {
4 +function isGossipSub (obj?: any): obj is GossipSub {
5 + if (obj == null) {
6 + return false
7 + }
8 +
9 + return typeof obj.publish === 'function' &&
10 + typeof obj.getSubscribers === 'function' &&
11 + typeof obj.unsubscribe === 'function' &&
12 + typeof obj.subscribe === 'function'
13 +}
14 +
15 +export function getPubSub (component: string, components: any): GossipSub {
16 const pubsub = components[component]
17
7 - if (!isPubSub(pubsub)) {
18 + if (!isGossipSub(pubsub)) {
19 throw new InvalidParametersError(`Component ${component} did not implement the PubSub interface`)
20 }
21
packages/libp2p-inspector-ui/package.json
+12 -11
@@ -153,23 +153,24 @@
153 "release": "aegir release"
154 },
155 "dependencies": {
156 - "@ipshipyard/libp2p-inspector-metrics": "^1.0.1",
157 - "@libp2p/interface": "^2.10.2",
158 - "@libp2p/peer-id": "^5.1.5",
159 - "@multiformats/multiaddr": "^12.4.0",
160 - "@multiformats/multiaddr-matcher": "^1.7.2",
161 - "multiformats": "^13.3.6",
156 + "@ipshipyard/libp2p-inspector-metrics": "^1.0.0",
157 + "@libp2p/gossipsub": "^15.0.11",
158 + "@libp2p/interface": "^3.1.0",
159 + "@libp2p/peer-id": "^6.0.4",
160 + "@multiformats/multiaddr": "^13.0.1",
161 + "@multiformats/multiaddr-matcher": "^3.0.1",
162 + "multiformats": "^13.4.2",
163 "react-icons": "^5.5.0",
164 "uint8arrays": "^5.1.0"
165 },
166 "devDependencies": {
166 - "@types/react": "^19.1.5",
167 - "@types/react-dom": "^19.1.5",
168 - "aegir": "^47.0.13",
167 + "@types/react": "^19.2.8",
168 + "@types/react-dom": "^19.2.3",
169 + "aegir": "^47.0.25",
170 "fast-glob": "^3.3.3"
171 },
172 "peerDependencies": {
172 - "react": "^19.1.0",
173 - "react-dom": "^19.1.0"
173 + "react": "^19.2.3",
174 + "react-dom": "^19.2.3"
175 }
176 }
packages/libp2p-inspector-ui/src/panels/multiaddr-list.tsx
+2 -2
@@ -1,6 +1,6 @@
1 import './multiaddr-list.css'
2 import { multiaddr } from '@multiformats/multiaddr'
3 -import { WebRTC, WebSockets, WebSocketsSecure, WebTransport, Circuit, QUIC, QUICV1, TCP, WebRTCDirect } from '@multiformats/multiaddr-matcher'
3 +import { WebRTC, WebSockets, WebSocketsSecure, WebTransport, Circuit, QUIC, QUIC_V1, TCP, WebRTCDirect } from '@multiformats/multiaddr-matcher'
4 import { useContext } from 'react'
5 import certifiedMultiaddr from '../../public/img/multiaddr-certified.svg'
6 import uncertifiedMultiaddr from '../../public/img/multiaddr-uncertified.svg'
@@ -31,7 +31,7 @@ function TransportIcon ({ multiaddr }: TransportIconProps): ReactElement {
31 src = websocketTransport
32 } else if (WebTransport.matches(multiaddr)) {
33 src = webtransportTransport
34 - } else if (QUIC.matches(multiaddr) || QUICV1.matches(multiaddr)) {
34 + } else if (QUIC.matches(multiaddr) || QUIC_V1.matches(multiaddr)) {
35 src = quicTransport
36 } else if (TCP.matches(multiaddr)) {
37 src = tcpTransport
packages/libp2p-inspector-ui/src/panels/node.tsx
+1 -1
@@ -43,7 +43,7 @@ export function Node ({ id, addresses, protocols, metadata }: NodeProps): ReactE
43 addresses={addresses.map(address => {
44 let multiaddr = address.multiaddr
45
46 - if (multiaddr.getPeerId() == null) {
46 + if (multiaddr.getComponents().some(c => c.name === 'p2p') === false) {
47 multiaddr = multiaddr.encapsulate(`/p2p/${id}`)
48 }
49
packages/libp2p-inspector-ui/src/panels/pubsub/index.tsx
+1 -1
@@ -5,7 +5,7 @@ import { Panel } from '../panel.js'
5 import { SmallError, SmallSuccess } from '../status.js'
6 import { TextInput } from '../text-input.js'
7 import type { MetricsRPC } from '@ipshipyard/libp2p-inspector-metrics'
8 -import type { Message } from '@libp2p/interface'
8 +import type { Message } from '@libp2p/gossipsub'
9 import type { ReactElement } from 'react'
10
11 export interface PubSubProps {
packages/libp2p-inspector/package.json
+19 -19
@@ -139,35 +139,35 @@
139 "release": "aegir release"
140 },
141 "dependencies": {
142 - "@ipshipyard/libp2p-inspector-metrics": "^1.0.1",
143 - "@ipshipyard/libp2p-inspector-ui": "^1.0.1",
144 - "@libp2p/interface": "^2.10.2",
145 - "@libp2p/peer-id": "^5.1.5",
146 - "@libp2p/utils": "^6.6.5",
147 - "@multiformats/multiaddr": "^12.4.0",
142 + "@ipshipyard/libp2p-inspector-metrics": "^1.0.0",
143 + "@ipshipyard/libp2p-inspector-ui": "^1.0.0",
144 + "@libp2p/interface": "^3.1.0",
145 + "@libp2p/peer-id": "^6.0.4",
146 + "@libp2p/utils": "^7.0.9",
147 + "@multiformats/multiaddr": "^13.0.1",
148 "@types/multicast-dns": "^7.2.4",
149 - "electron": "^36.3.1",
149 + "electron": "^40.0.0",
150 "it-length-prefixed": "^10.0.1",
151 "it-pipe": "^3.0.1",
152 "it-pushable": "^3.2.3",
153 - "it-rpc": "^1.1.0",
153 + "it-rpc": "^1.2.1",
154 "multicast-dns": "^7.2.5",
155 - "multiformats": "^13.3.6",
156 - "race-signal": "^1.1.3",
157 - "react": "^19.1.0",
158 - "react-dom": "^19.1.0",
155 + "multiformats": "^13.4.2",
156 + "race-signal": "^2.0.0",
157 + "react": "^19.2.3",
158 + "react-dom": "^19.2.3",
159 "react-icons": "^5.5.0",
160 "stream-to-it": "^1.0.1",
161 "uint8arrays": "^5.1.0"
162 },
163 "devDependencies": {
164 - "@libp2p/webrtc": "^5.2.15",
165 - "@playwright/test": "^1.52.0",
166 - "@types/react": "^19.1.5",
167 - "@types/react-dom": "^19.1.5",
168 - "aegir": "^47.0.13",
164 + "@libp2p/webrtc": "^6.0.10",
165 + "@playwright/test": "^1.57.0",
166 + "@types/react": "^19.2.8",
167 + "@types/react-dom": "^19.2.3",
168 + "aegir": "^47.0.25",
169 "fast-glob": "^3.3.3",
170 - "libp2p": "^2.8.8",
171 - "playwright-core": "^1.52.0"
170 + "libp2p": "^3.1.2",
171 + "playwright-core": "^1.57.0"
172 }
173 }
packages/libp2p-inspector/src/main/discovery.ts
+1 -1
@@ -1,5 +1,5 @@
1 import { peerIdFromString } from '@libp2p/peer-id'
2 -import { repeatingTask } from '@libp2p/utils/repeating-task'
2 +import { repeatingTask } from '@libp2p/utils'
3 import { multiaddr } from '@multiformats/multiaddr'
4 import multicastDNS from 'multicast-dns'
5 import { Target } from './target.js'
packages/libp2p-inspector/src/main/target.ts
+11 -2
@@ -1,6 +1,7 @@
1 import { createConnection } from 'node:net'
2 import { SOURCE_CLIENT } from '@ipshipyard/libp2p-inspector-metrics'
3 -import { Queue } from '@libp2p/utils/queue'
3 +import { InvalidParametersError } from '@libp2p/interface'
4 +import { getNetConfig, Queue } from '@libp2p/utils'
5 import { encode, decode } from 'it-length-prefixed'
6 import { pushable } from 'it-pushable'
7 import { base64 } from 'multiformats/bases/base64'
@@ -105,8 +106,16 @@ export class Target {
106
107 private async _openConnection (ma: Multiaddr, options?: AbortOptions): Promise<void> {
108 const result = Promise.withResolvers<void>()
109 + const config = getNetConfig(ma)
110
109 - const socket = createConnection(ma.toOptions(), () => {
111 + if (config.port == null) {
112 + throw new InvalidParametersError('Port was missing from multiaddr')
113 + }
114 +
115 + const socket = createConnection({
116 + host: config.host,
117 + port: config.port
118 + }, () => {
119 this.source = pushable()
120
121 const duplexSocket = duplex(socket)
packages/libp2p-inspector/test/fixtures/get-libp2p.ts
+4 -4
@@ -1,11 +1,10 @@
1 import { inspectorMetrics } from '@ipshipyard/libp2p-inspector-metrics'
2 -import { mergeOptions } from '@libp2p/utils/merge-options'
2 import { webRTCDirect } from '@libp2p/webrtc'
3 import { createLibp2p } from 'libp2p'
4 import type { Libp2p, Libp2pOptions } from 'libp2p'
5
6 export function getLibp2p (config: Libp2pOptions = {}): Promise<Libp2p> {
8 - return createLibp2p(mergeOptions({
7 + return createLibp2p({
8 metrics: inspectorMetrics(),
9 addresses: {
10 listen: [
@@ -14,6 +13,7 @@ export function getLibp2p (config: Libp2pOptions = {}): Promise<Libp2p> {
13 },
14 transports: [
15 webRTCDirect()
17 - ]
18 - }, config))
16 + ],
17 + ...config
18 + })
19 }