libp2p 2.1.3 → 2.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/index.min.js +10 -10
  2. package/dist/src/config.d.ts.map +1 -1
  3. package/dist/src/config.js +1 -3
  4. package/dist/src/config.js.map +1 -1
  5. package/dist/src/connection/index.d.ts.map +1 -1
  6. package/dist/src/connection/index.js +4 -6
  7. package/dist/src/connection/index.js.map +1 -1
  8. package/dist/src/connection-manager/address-sorter.d.ts +25 -0
  9. package/dist/src/connection-manager/address-sorter.d.ts.map +1 -0
  10. package/dist/src/connection-manager/address-sorter.js +112 -0
  11. package/dist/src/connection-manager/address-sorter.js.map +1 -0
  12. package/dist/src/connection-manager/connection-pruner.d.ts +4 -1
  13. package/dist/src/connection-manager/connection-pruner.d.ts.map +1 -1
  14. package/dist/src/connection-manager/connection-pruner.js +13 -7
  15. package/dist/src/connection-manager/connection-pruner.js.map +1 -1
  16. package/dist/src/connection-manager/dial-queue.d.ts +1 -1
  17. package/dist/src/connection-manager/dial-queue.d.ts.map +1 -1
  18. package/dist/src/connection-manager/dial-queue.js +4 -5
  19. package/dist/src/connection-manager/dial-queue.js.map +1 -1
  20. package/dist/src/connection-manager/index.d.ts +0 -1
  21. package/dist/src/connection-manager/index.d.ts.map +1 -1
  22. package/dist/src/connection-manager/index.js +30 -40
  23. package/dist/src/connection-manager/index.js.map +1 -1
  24. package/dist/src/upgrader.d.ts.map +1 -1
  25. package/dist/src/upgrader.js +23 -21
  26. package/dist/src/upgrader.js.map +1 -1
  27. package/dist/src/version.d.ts +1 -1
  28. package/dist/src/version.js +1 -1
  29. package/package.json +12 -12
  30. package/src/config.ts +1 -3
  31. package/src/connection/index.ts +5 -11
  32. package/src/connection-manager/address-sorter.ts +137 -0
  33. package/src/connection-manager/connection-pruner.ts +16 -8
  34. package/src/connection-manager/dial-queue.ts +5 -6
  35. package/src/connection-manager/index.ts +38 -40
  36. package/src/upgrader.ts +25 -16
  37. package/src/version.ts +1 -1
@@ -0,0 +1,137 @@
1
+ import { isPrivate } from '@libp2p/utils/multiaddr/is-private'
2
+ import { Circuit, WebSockets, WebSocketsSecure, WebRTC, WebRTCDirect, WebTransport, TCP } from '@multiformats/multiaddr-matcher'
3
+ import type { Address } from '@libp2p/interface'
4
+
5
+ /**
6
+ * Sorts addresses by order of reliability, where they have presented the fewest
7
+ * problems:
8
+ *
9
+ * TCP -> WebSockets/Secure -> WebRTC -> WebRTCDirect -> WebTransport
10
+ */
11
+ // eslint-disable-next-line complexity
12
+ export function reliableTransportsFirst (a: Address, b: Address): -1 | 0 | 1 {
13
+ const isATCP = TCP.exactMatch(a.multiaddr)
14
+ const isBTCP = TCP.exactMatch(b.multiaddr)
15
+
16
+ if (isATCP && !isBTCP) {
17
+ return -1
18
+ }
19
+
20
+ if (!isATCP && isBTCP) {
21
+ return 1
22
+ }
23
+
24
+ const isAWebSocketSecure = WebSocketsSecure.exactMatch(a.multiaddr)
25
+ const isBWebSocketSecure = WebSocketsSecure.exactMatch(b.multiaddr)
26
+
27
+ if (isAWebSocketSecure && !isBWebSocketSecure) {
28
+ return -1
29
+ }
30
+
31
+ if (!isAWebSocketSecure && isBWebSocketSecure) {
32
+ return 1
33
+ }
34
+
35
+ const isAWebSocket = WebSockets.exactMatch(a.multiaddr)
36
+ const isBWebSocket = WebSockets.exactMatch(b.multiaddr)
37
+
38
+ if (isAWebSocket && !isBWebSocket) {
39
+ return -1
40
+ }
41
+
42
+ if (!isAWebSocket && isBWebSocket) {
43
+ return 1
44
+ }
45
+
46
+ const isAWebRTC = WebRTC.exactMatch(a.multiaddr)
47
+ const isBWebRTC = WebRTC.exactMatch(b.multiaddr)
48
+
49
+ if (isAWebRTC && !isBWebRTC) {
50
+ return -1
51
+ }
52
+
53
+ if (!isAWebRTC && isBWebRTC) {
54
+ return 1
55
+ }
56
+
57
+ const isAWebRTCDirect = WebRTCDirect.exactMatch(a.multiaddr)
58
+ const isBWebRTCDirect = WebRTCDirect.exactMatch(b.multiaddr)
59
+
60
+ if (isAWebRTCDirect && !isBWebRTCDirect) {
61
+ return -1
62
+ }
63
+
64
+ if (!isAWebRTCDirect && isBWebRTCDirect) {
65
+ return 1
66
+ }
67
+
68
+ const isAWebTransport = WebTransport.exactMatch(a.multiaddr)
69
+ const isBWebTransport = WebTransport.exactMatch(b.multiaddr)
70
+
71
+ if (isAWebTransport && !isBWebTransport) {
72
+ return -1
73
+ }
74
+
75
+ if (!isAWebTransport && isBWebTransport) {
76
+ return 1
77
+ }
78
+
79
+ // ... everything else
80
+ return 0
81
+ }
82
+
83
+ /**
84
+ * Compare function for array.sort() that moves public addresses to the start
85
+ * of the array.
86
+ */
87
+ export function publicAddressesFirst (a: Address, b: Address): -1 | 0 | 1 {
88
+ const isAPrivate = isPrivate(a.multiaddr)
89
+ const isBPrivate = isPrivate(b.multiaddr)
90
+
91
+ if (isAPrivate && !isBPrivate) {
92
+ return 1
93
+ } else if (!isAPrivate && isBPrivate) {
94
+ return -1
95
+ }
96
+
97
+ return 0
98
+ }
99
+
100
+ /**
101
+ * Compare function for array.sort() that moves certified addresses to the start
102
+ * of the array.
103
+ */
104
+ export function certifiedAddressesFirst (a: Address, b: Address): -1 | 0 | 1 {
105
+ if (a.isCertified && !b.isCertified) {
106
+ return -1
107
+ } else if (!a.isCertified && b.isCertified) {
108
+ return 1
109
+ }
110
+
111
+ return 0
112
+ }
113
+
114
+ /**
115
+ * Compare function for array.sort() that moves circuit relay addresses to the
116
+ * end of the array.
117
+ */
118
+ export function circuitRelayAddressesLast (a: Address, b: Address): -1 | 0 | 1 {
119
+ const isACircuit = Circuit.exactMatch(a.multiaddr)
120
+ const isBCircuit = Circuit.exactMatch(b.multiaddr)
121
+
122
+ if (isACircuit && !isBCircuit) {
123
+ return 1
124
+ } else if (!isACircuit && isBCircuit) {
125
+ return -1
126
+ }
127
+
128
+ return 0
129
+ }
130
+
131
+ export function defaultAddressSorter (addresses: Address[]): Address[] {
132
+ return addresses
133
+ .sort(reliableTransportsFirst)
134
+ .sort(certifiedAddressesFirst)
135
+ .sort(circuitRelayAddressesLast)
136
+ .sort(publicAddressesFirst)
137
+ }
@@ -40,21 +40,29 @@ export class ConnectionPruner {
40
40
  this.peerStore = components.peerStore
41
41
  this.events = components.events
42
42
  this.log = components.logger.forComponent('libp2p:connection-manager:connection-pruner')
43
+ this.maybePruneConnections = this.maybePruneConnections.bind(this)
44
+ }
43
45
 
44
- // check the max connection limit whenever a peer connects
45
- components.events.addEventListener('connection:open', () => {
46
- this.maybePruneConnections()
47
- .catch(err => {
48
- this.log.error(err)
49
- })
50
- })
46
+ start (): void {
47
+ this.events.addEventListener('connection:open', this.maybePruneConnections)
48
+ }
49
+
50
+ stop (): void {
51
+ this.events.removeEventListener('connection:open', this.maybePruneConnections)
52
+ }
53
+
54
+ maybePruneConnections (): void {
55
+ this._maybePruneConnections()
56
+ .catch(err => {
57
+ this.log.error('error while pruning connections %e', err)
58
+ })
51
59
  }
52
60
 
53
61
  /**
54
62
  * If we have more connections than our maximum, select some excess connections
55
63
  * to prune based on peer value
56
64
  */
57
- async maybePruneConnections (): Promise<void> {
65
+ private async _maybePruneConnections (): Promise<void> {
58
66
  const connections = this.connectionManager.getConnections()
59
67
  const numConnections = connections.length
60
68
 
@@ -1,7 +1,6 @@
1
1
  /* eslint-disable max-depth */
2
2
  import { TimeoutError, DialError, setMaxListeners, AbortError } from '@libp2p/interface'
3
3
  import { PeerMap } from '@libp2p/peer-collections'
4
- import { defaultAddressSort } from '@libp2p/utils/address-sort'
5
4
  import { PriorityQueue, type PriorityQueueJobOptions } from '@libp2p/utils/priority-queue'
6
5
  import { type Multiaddr, type Resolver, resolvers, multiaddr } from '@multiformats/multiaddr'
7
6
  import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
@@ -11,6 +10,7 @@ import { CustomProgressEvent } from 'progress-events'
11
10
  import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
12
11
  import { DialDeniedError, NoValidAddressesError } from '../errors.js'
13
12
  import { getPeerAddress } from '../get-peer.js'
13
+ import { defaultAddressSorter } from './address-sorter.js'
14
14
  import {
15
15
  DIAL_TIMEOUT,
16
16
  MAX_PARALLEL_DIALS,
@@ -47,7 +47,6 @@ interface DialerInit {
47
47
  }
48
48
 
49
49
  const defaultOptions = {
50
- addressSorter: defaultAddressSort,
51
50
  maxParallelDials: MAX_PARALLEL_DIALS,
52
51
  maxDialQueueLength: MAX_DIAL_QUEUE_LENGTH,
53
52
  maxPeerAddrsToDial: MAX_PEER_ADDRS_TO_DIAL,
@@ -71,7 +70,7 @@ interface DialQueueComponents {
71
70
  export class DialQueue {
72
71
  public queue: PriorityQueue<Connection, DialQueueJobOptions>
73
72
  private readonly components: DialQueueComponents
74
- private readonly addressSorter: AddressSorter
73
+ private readonly addressSorter?: AddressSorter
75
74
  private readonly maxPeerAddrsToDial: number
76
75
  private readonly maxDialQueueLength: number
77
76
  private readonly dialTimeout: number
@@ -80,7 +79,7 @@ export class DialQueue {
80
79
  private readonly log: Logger
81
80
 
82
81
  constructor (components: DialQueueComponents, init: DialerInit = {}) {
83
- this.addressSorter = init.addressSorter ?? defaultOptions.addressSorter
82
+ this.addressSorter = init.addressSorter
84
83
  this.maxPeerAddrsToDial = init.maxPeerAddrsToDial ?? defaultOptions.maxPeerAddrsToDial
85
84
  this.maxDialQueueLength = init.maxDialQueueLength ?? defaultOptions.maxDialQueueLength
86
85
  this.dialTimeout = init.dialTimeout ?? defaultOptions.dialTimeout
@@ -153,7 +152,7 @@ export class DialQueue {
153
152
  })
154
153
  })
155
154
 
156
- if (existingConnection != null) {
155
+ if (existingConnection?.status === 'open') {
157
156
  this.log('already connected to %a', existingConnection.remoteAddr)
158
157
  options.onProgress?.(new CustomProgressEvent('dial-queue:already-connected'))
159
158
  return existingConnection
@@ -467,7 +466,7 @@ export class DialQueue {
467
466
  gatedAdrs.push(addr)
468
467
  }
469
468
 
470
- const sortedGatedAddrs = gatedAdrs.sort(this.addressSorter)
469
+ const sortedGatedAddrs = this.addressSorter == null ? defaultAddressSorter(gatedAdrs) : gatedAdrs.sort(this.addressSorter)
471
470
 
472
471
  // make sure we actually have some addresses to dial
473
472
  if (sortedGatedAddrs.length === 0) {
@@ -1,6 +1,5 @@
1
- import { InvalidMultiaddrError, InvalidParametersError, InvalidPeerIdError, NotStartedError, start, stop } from '@libp2p/interface'
1
+ import { ConnectionClosedError, InvalidMultiaddrError, InvalidParametersError, InvalidPeerIdError, NotStartedError, start, stop } from '@libp2p/interface'
2
2
  import { PeerMap } from '@libp2p/peer-collections'
3
- import { defaultAddressSort } from '@libp2p/utils/address-sort'
4
3
  import { RateLimiter } from '@libp2p/utils/rate-limiter'
5
4
  import { type Multiaddr, type Resolver, multiaddr } from '@multiformats/multiaddr'
6
5
  import { dnsaddrResolver } from '@multiformats/multiaddr/resolvers'
@@ -214,8 +213,6 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
214
213
 
215
214
  this.onConnect = this.onConnect.bind(this)
216
215
  this.onDisconnect = this.onDisconnect.bind(this)
217
- this.events.addEventListener('connection:open', this.onConnect)
218
- this.events.addEventListener('connection:close', this.onDisconnect)
219
216
 
220
217
  // allow/deny lists
221
218
  this.allow = (init.allow ?? []).map(ma => multiaddr(ma))
@@ -242,7 +239,7 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
242
239
  })
243
240
 
244
241
  this.dialQueue = new DialQueue(components, {
245
- addressSorter: init.addressSorter ?? defaultAddressSort,
242
+ addressSorter: init.addressSorter,
246
243
  maxParallelDials: init.maxParallelDials ?? MAX_PARALLEL_DIALS,
247
244
  maxDialQueueLength: init.maxDialQueueLength ?? MAX_DIAL_QUEUE_LENGTH,
248
245
  maxPeerAddrsToDial: init.maxPeerAddrsToDial ?? MAX_PEER_ADDRS_TO_DIAL,
@@ -268,10 +265,6 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
268
265
 
269
266
  readonly [Symbol.toStringTag] = '@libp2p/connection-manager'
270
267
 
271
- isStarted (): boolean {
272
- return this.started
273
- }
274
-
275
268
  /**
276
269
  * Starts the Connection Manager. If Metrics are not enabled on libp2p
277
270
  * only event loop and connection limits will be monitored.
@@ -288,11 +281,7 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
288
281
 
289
282
  for (const conns of this.connections.values()) {
290
283
  for (const conn of conns) {
291
- if (conn.direction === 'inbound') {
292
- metric.inbound++
293
- } else {
294
- metric.outbound++
295
- }
284
+ metric[conn.direction]++
296
285
  }
297
286
  }
298
287
 
@@ -356,9 +345,13 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
356
345
  }
357
346
  })
358
347
 
348
+ this.events.addEventListener('connection:open', this.onConnect)
349
+ this.events.addEventListener('connection:close', this.onDisconnect)
350
+
359
351
  await start(
360
352
  this.dialQueue,
361
- this.reconnectQueue
353
+ this.reconnectQueue,
354
+ this.connectionPruner
362
355
  )
363
356
 
364
357
  this.started = true
@@ -369,9 +362,13 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
369
362
  * Stops the Connection Manager
370
363
  */
371
364
  async stop (): Promise<void> {
365
+ this.events.removeEventListener('connection:open', this.onConnect)
366
+ this.events.removeEventListener('connection:close', this.onDisconnect)
367
+
372
368
  await stop(
373
369
  this.reconnectQueue,
374
- this.dialQueue
370
+ this.dialQueue,
371
+ this.connectionPruner
375
372
  )
376
373
 
377
374
  // Close all connections we're tracking
@@ -413,17 +410,19 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
413
410
  return
414
411
  }
415
412
 
416
- const peerId = connection.remotePeer
417
- const storedConns = this.connections.get(peerId)
418
- let isNewPeer = false
419
-
420
- if (storedConns != null) {
421
- storedConns.push(connection)
422
- } else {
423
- isNewPeer = true
424
- this.connections.set(peerId, [connection])
413
+ if (connection.status !== 'open') {
414
+ // this can happen when the remote closes the connection immediately after
415
+ // opening
416
+ return
425
417
  }
426
418
 
419
+ const peerId = connection.remotePeer
420
+ const isNewPeer = !this.connections.has(peerId)
421
+ const storedConns = this.connections.get(peerId) ?? []
422
+ storedConns.push(connection)
423
+
424
+ this.connections.set(peerId, storedConns)
425
+
427
426
  // only need to store RSA public keys, all other types are embedded in the peer id
428
427
  if (peerId.publicKey != null && peerId.type === 'RSA') {
429
428
  await this.peerStore.patch(peerId, {
@@ -441,20 +440,21 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
441
440
  */
442
441
  onDisconnect (evt: CustomEvent<Connection>): void {
443
442
  const { detail: connection } = evt
443
+ const peerId = connection.remotePeer
444
+ const peerConns = this.connections.get(peerId) ?? []
444
445
 
445
- if (!this.started) {
446
- // This can happen when we are in the process of shutting down the node
447
- return
448
- }
446
+ // remove closed connection
447
+ const filteredPeerConns = peerConns.filter(conn => conn.id !== connection.id)
449
448
 
450
- const peerId = connection.remotePeer
451
- let storedConn = this.connections.get(peerId)
449
+ // update peer connections
450
+ this.connections.set(peerId, filteredPeerConns)
452
451
 
453
- if (storedConn != null && storedConn.length > 1) {
454
- storedConn = storedConn.filter((conn) => conn.id !== connection.id)
455
- this.connections.set(peerId, storedConn)
456
- } else if (storedConn != null) {
452
+ if (filteredPeerConns.length === 0) {
453
+ // trigger disconnect event if no connections remain
454
+ this.log('onDisconnect remove all connections for peer %p', peerId)
457
455
  this.connections.delete(peerId)
456
+
457
+ // broadcast disconnect event
458
458
  this.events.safeDispatchEvent('peer:disconnect', { detail: connection.remotePeer })
459
459
  }
460
460
  }
@@ -478,7 +478,7 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
478
478
  }
479
479
 
480
480
  async openConnection (peerIdOrMultiaddr: PeerId | Multiaddr | Multiaddr[], options: OpenConnectionOptions = {}): Promise<Connection> {
481
- if (!this.isStarted()) {
481
+ if (!this.started) {
482
482
  throw new NotStartedError('Not started')
483
483
  }
484
484
 
@@ -508,10 +508,8 @@ export class DefaultConnectionManager implements ConnectionManager, Startable {
508
508
  priority: options.priority ?? DEFAULT_DIAL_PRIORITY
509
509
  })
510
510
 
511
- if (connection.remotePeer.equals(this.peerId)) {
512
- const err = new InvalidPeerIdError('Can not dial self')
513
- connection.abort(err)
514
- throw err
511
+ if (connection.status !== 'open') {
512
+ throw new ConnectionClosedError('Remote closed connection during opening')
515
513
  }
516
514
 
517
515
  let peerConnections = this.connections.get(connection.remotePeer)
package/src/upgrader.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { InvalidMultiaddrError, TooManyInboundProtocolStreamsError, TooManyOutboundProtocolStreamsError, LimitedConnectionError, setMaxListeners } from '@libp2p/interface'
1
+ import { InvalidMultiaddrError, TooManyInboundProtocolStreamsError, TooManyOutboundProtocolStreamsError, LimitedConnectionError, setMaxListeners, InvalidPeerIdError } from '@libp2p/interface'
2
2
  import * as mss from '@libp2p/multistream-select'
3
3
  import { peerIdFromString } from '@libp2p/peer-id'
4
4
  import { anySignal } from 'any-signal'
@@ -304,6 +304,14 @@ export class DefaultUpgrader implements Upgrader {
304
304
  remotePeer = remotePeerId
305
305
  }
306
306
 
307
+ // this can happen if we dial a multiaddr without a peer id, we only find
308
+ // out the identity of the remote after the connection is encrypted
309
+ if (remotePeer.equals(this.components.peerId)) {
310
+ const err = new InvalidPeerIdError('Can not dial self')
311
+ maConn.abort(err)
312
+ throw err
313
+ }
314
+
307
315
  upgradedConn = encryptedConn
308
316
  if (opts?.muxerFactory != null) {
309
317
  muxerFactory = opts.muxerFactory
@@ -326,6 +334,8 @@ export class DefaultUpgrader implements Upgrader {
326
334
  } catch (err: any) {
327
335
  maConn.log.error('failed to upgrade inbound connection %s %a - %e', direction === 'inbound' ? 'from' : 'to', maConn.remoteAddr, err)
328
336
  throw err
337
+ } finally {
338
+ signal.clear()
329
339
  }
330
340
 
331
341
  await this.shouldBlockConnection(direction === 'inbound' ? 'denyInboundUpgradedConnection' : 'denyOutboundUpgradedConnection', remotePeer, maConn)
@@ -538,7 +548,7 @@ export class DefaultUpgrader implements Upgrader {
538
548
  const _timeline = maConn.timeline
539
549
  maConn.timeline = new Proxy(_timeline, {
540
550
  set: (...args) => {
541
- if (connection != null && args[1] === 'close' && args[2] != null && _timeline.close == null) {
551
+ if (args[1] === 'close' && args[2] != null && _timeline.close == null) {
542
552
  // Wait for close to finish before notifying of the closure
543
553
  (async () => {
544
554
  try {
@@ -546,14 +556,14 @@ export class DefaultUpgrader implements Upgrader {
546
556
  await connection.close()
547
557
  }
548
558
  } catch (err: any) {
549
- connection.log.error('error closing connection after timeline close', err)
559
+ connection.log.error('error closing connection after timeline close %e', err)
550
560
  } finally {
551
561
  this.events.safeDispatchEvent('connection:close', {
552
562
  detail: connection
553
563
  })
554
564
  }
555
565
  })().catch(err => {
556
- connection.log.error('error thrown while dispatching connection:close event', err)
566
+ connection.log.error('error thrown while dispatching connection:close event %e', err)
557
567
  })
558
568
  }
559
569
 
@@ -578,25 +588,21 @@ export class DefaultUpgrader implements Upgrader {
578
588
  limits,
579
589
  logger: this.components.logger,
580
590
  newStream: newStream ?? errConnectionNotMultiplexed,
581
- getStreams: () => { if (muxer != null) { return muxer.streams } else { return [] } },
591
+ getStreams: () => {
592
+ return muxer?.streams ?? []
593
+ },
582
594
  close: async (options?: AbortOptions) => {
583
- // Ensure remaining streams are closed gracefully
584
- if (muxer != null) {
585
- connection.log.trace('close muxer')
586
- await muxer.close(options)
587
- }
595
+ // ensure remaining streams are closed gracefully
596
+ await muxer?.close(options)
588
597
 
589
- connection.log.trace('close maconn')
590
598
  // close the underlying transport
591
599
  await maConn.close(options)
592
- connection.log.trace('closed maconn')
593
600
  },
594
601
  abort: (err) => {
595
602
  maConn.abort(err)
596
- // Ensure remaining streams are aborted
597
- if (muxer != null) {
598
- muxer.abort(err)
599
- }
603
+
604
+ // ensure remaining streams are aborted
605
+ muxer?.abort(err)
600
606
  }
601
607
  })
602
608
 
@@ -604,6 +610,9 @@ export class DefaultUpgrader implements Upgrader {
604
610
  detail: connection
605
611
  })
606
612
 
613
+ // @ts-expect-error nah
614
+ connection.__maConnTimeline = _timeline
615
+
607
616
  return connection
608
617
  }
609
618
 
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
- export const version = '2.1.3'
1
+ export const version = '2.1.4'
2
2
  export const name = 'libp2p'