<!--Specify versions for migration below-->
# Migrating to libp2p@37 <!-- omit in toc -->

A migration guide for refactoring your application code from libp2p v0.36.x to v0.37.0.

## Table of Contents <!-- omit in toc -->

- [ESM](#esm)
- [TypeScript](#typescript)
- [Config](#config)
- [Bundled modules](#bundled-modules)
- [Events](#events)
- [Pubsub](#pubsub)

## ESM

The biggest change to `libp2p@0.37.0` is that the module is now [ESM-only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c).

ESM is the module system for JavaScript, it allows us to structure our code in separate files without polluting a global namespace.

Other systems have tried to fill this gap, notably CommonJS, AMD, RequireJS and others, but ESM is [the official standard format](https://tc39.es/ecma262/#sec-modules) to package JavaScript code for reuse.

## TypeScript

The core `libp2p` module and all supporting modules have now been ported to TypeScript in a complete ground-up rewrite. This will not have a huge impact on most application code, but those that are type-aware, either by being written in TypeScript themselves or using JSDoc comments will notice full type completion and better error message when coding against the libp2p API.

To reflect the updated nature of these modules, all ecosystem modules have been moved to the `@libp2p` org on npm, so `libp2p-tcp` has become `@libp2p/tcp`, `libp2p-mplex` has become `@libp2p/mplex` and so on. `@chainsafe/libp2p-noise` and `libp2p-gossipsub` are unaffected.

## Config

Because libp2p is now fully typed it was necessary to refactor the configuration object passed to the libp2p constructor. The reason being, it previously accepted config objects to pass to the constructors of the various modules - to type those we'd need to know the types of all possible modules in advance which isn't possible.

The following changes have been made to the configuration object:

1. It now takes instances of modules rather than their classes
2. Keys from the `config` and `modules` objects have been migrated to the root of the object
3. Use of the `enabled` flag has been removed - if you don't want a particular feature enabled, don't pass a module implementing that feature
4. Some keys have been renamed = `transport` -> `transports`, `streamMuxer` -> `streamMuxers`, `connEncryption` -> `connectionEncryption`, etc
5. Keys from `config.dialer` have been moved to `config.connectionManager` as the connection manager is now responsible for managing connections
6. The `protocolPrefix` configuration option is now passed on a per-protocol basis for `identify`, `fetch` and `ping`

**Before**

```js
import Libp2p from 'libp2p'
import TCP from 'libp2p-tcp'
import Mplex from 'libp2p-mplex'
import { NOISE } from '@chainsafe/libp2p-noise'
import Gossipsub from 'libp2p-gossipsub'
import KadDHT from 'libp2p-kad-dht'
import Bootstrap from 'libp2p-bootstrap'
import MulticastDNS from 'libp2p-mdns'

const node = await Libp2p.create({
  addresses: {
    listen: ['/ip4/127.0.0.1/tcp/8000']
  },
  modules: {
    transport: [
      TCP
    ],
    streamMuxer: [
      Mplex
    ],
    connEncryption: [
      NOISE
    ],
    dht: KadDHT,
    pubsub: Gossipsub,
    peerDiscovery: [
      Bootstrap,
      MulticastDNS
    ]
  },
  protocolPrefix: 'ipfs',
  config: {
    peerDiscovery: {
      autoDial: true,
      [MulticastDNS.tag]: {
        interval: 1000,
        enabled: true
      },
      [Bootstrap.tag]: {
        list: [
          // .. multiaddrs here
        ],
        interval: 2000,
        enabled: true
      }
    },
    dialer: {
      dialTimeout: 60000
    }
  }
})
```

**After**

```js
import { createLibp2p } from 'libp2p'
import { TCP } from '@libp2p/tcp'
import { Mplex } from '@libp2p/mplex'
import { Noise } from '@chainsafe/libp2p-noise'
import Gossipsub from '@chainsafe/libp2p-gossipsub'
import { KadDHT } from '@libp2p/kad-dht'
import { Bootstrap } from '@libp2p/bootstrap'
import { MulticastDNS } from '@libp2p/mdns'

const node = await createLibp2p({
  addresses: {
    listen: ['/ip4/127.0.0.1/tcp/8000']
  },
  addressManager: {
    autoDial: true
  },
  connectionManager: {
    dialTimeout: 60000
  },
  transports: [
    new TCP()
  ],
  streamMuxers: [
    new Mplex()
  ],
  connectionEncryption: [
    new Noise()
  ],
  dht: new KadDHT(),
  pubsub: new Gossipsub(),
  peerDiscovery: [
    new Bootstrap({
      list: [
        // .. multiaddrs here
      ],
      interval: 2000
    }),
    new MulticastDNS({
      interval: 1000
    })
  ],
  identify: {
    protocolPrefix: 'ipfs'
  }
})
```

## Bundled modules

Previously you'd have to use deep import paths to get at bundled modules such as the private network module.

Access to these modules is now controlled by the package.json export map so your import paths will need to be updated:

**Before**

```js
import plaintext from 'libp2p/src/insecure/plaintext.js'
import Protector from 'libp2p/src/pnet/index.js'
import generateKey from 'libp2p/src/pnet/key-generator.js'
import TransportManager from 'libp2p/src/transport-manager.js'
```

**After**

```js
import { Plaintext } from 'libp2p/insecure'
import { PreSharedKeyConnectionProtector, generateKey } from 'libp2p/pnet'
import { TransportManager } from 'libp2p/transport-manager'
```

## Events

To reduce our dependency on Node.js internals, use of [EventEmitter](https://nodejs.org/api/events.html#class-eventemitter) has been replaced with the standard [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget).

The EventTarget API is very similar to [HTML DOM Events](https://developer.mozilla.org/en-US/docs/Web/API/Event) used by the browser.

All events are instances of the [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) class. Event-specific information can be accessed via the `.detail` property of the passed event.

They type of event emitted can be inferred from the types for each event emitter.

**Before**

```js
const handler = (peerInfo) => {
  //...
}

// listen for event
libp2p.on('peer:discovery', handler)

// stop listening for event
libp2p.removeListener('peer:discovery', handler)
libp2p.off('peer:discovery', handler)
```

**After**

```js
const handler = (event) => {
  const peerInfo = event.detail
  //...
}

// listen for event
libp2p.addEventListener('peer:discovery', handler)

// stop listening for event
libp2p.removeEventListener('peer:discovery', handler)
```

## Pubsub

Similar to the events refactor above, pubsub is now driven by the standard [EventTarget](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) API.

You can still subscribe to events without a listener with `.subscribe` but all other uses now use the standard API.

Similar to the other events emitted by libp2p the event type is [CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent). This is part of the js language but at the time of writing Node.js [does not support](https://github.com/nodejs/node/issues/40678) `CustomEvent`, so a polyfill is supplied as part of the `@libp2p/interfaces`

**Before**

```js
const handler = (message: Message) => {
  const topic = message.topic

  //...
}

// listen for event
libp2p.pubsub.subscribe('my-topic')
libp2p.pubsub.on('my-topic', handler)

// send event
libp2p.pubsub.emit('my-topic', Uint8Array.from([0, 1, 2, 3]))

// stop listening for event
libp2p.unsubscribe('my-topic', handler)
libp2p.pubsub.off('my-topic', handler)
```

**After**

```js
import type { Message } from '@libp2p/interface/pubsub'

const handler = (event: CustomEvent<Message>) => {
  const message = event.detail
  const topic = message.topic

  //...
}

// listen for event
libp2p.pubsub.subscribe('my-topic')
libp2p.pubsub.addEventListener('message', handler)

// send event
libp2p.pubsub.publish('my-topic', Uint8Array.from([0, 1, 2, 3]))

// stop listening for event
libp2p.pubsub.unsubscribe('my-topic')
libp2p.pubsub.removeEventListener('message', handler)
```
