# multistream-select

> JavaScript implementation of multistream-select

Latest version **3.0.2** (published 2021-12-21) · MIT license · 0 weekly downloads

## Install

```sh
npm install multistream-select
pnpm add multistream-select
yarn add multistream-select
bun add multistream-select
```

## Health

**Score 25/100 (F)** — status: abandoned.

Positive: has types; no vulnerabilities; high quality score.

Warnings: low downloads; no esm support.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 3.0.2 |
| Published | 2021-12-21 |
| First published | 2015-06-08 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | bundled |
| Module format | CommonJS |
| Dependencies | 11 |
| Unpacked size | 95 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| GitHub stars | 29 |
| Maintainers | jacobheun, daviddias, achingbrain, vascosantos |
| Keywords | stream, multistream, protocol, ipfs, libp2p |

## Links

- npm: https://www.npmjs.com/package/multistream-select
- Repository: https://github.com/multiformats/js-multistream-select
- Homepage: https://github.com/multiformats/js-multistream-select#readme
- Issues: https://github.com/multiformats/js-multistream-select/issues
- npm.io page: https://npm.io/package/multistream-select

## Dependencies (11)

- [bl](https://npm.io/package/bl.md) ^5.0.0
- [debug](https://npm.io/package/debug.md) ^4.1.1
- [it-pipe](https://npm.io/package/it-pipe.md) ^1.0.1
- [p-defer](https://npm.io/package/p-defer.md) ^3.0.0
- [err-code](https://npm.io/package/err-code.md) ^3.0.1
- [it-first](https://npm.io/package/it-first.md) ^1.0.6
- [it-reader](https://npm.io/package/it-reader.md) ^3.0.0
- [uint8arrays](https://npm.io/package/uint8arrays.md) ^3.0.0
- [it-handshake](https://npm.io/package/it-handshake.md) ^2.0.0
- [abortable-iterator](https://npm.io/package/abortable-iterator.md) ^3.0.0
- [it-length-prefixed](https://npm.io/package/it-length-prefixed.md) ^5.0.0

## Alternatives

- [byte-size](https://npm.io/package/byte-size.md) — 2.1M weekly downloads
- [speed-limiter](https://npm.io/package/speed-limiter.md) — 16.0K weekly downloads
- [@powersync/node](https://npm.io/package/@powersync/node.md) — 10.9K weekly downloads
- [@ledgerhq/coin-cardano](https://npm.io/package/@ledgerhq/coin-cardano.md) — 1.0K weekly downloads
- [@jayesol/jayeson.lib.streamfinder](https://npm.io/package/@jayesol/jayeson.lib.streamfinder.md) — 1.0K weekly downloads

## Recent versions

- 3.0.2 (latest) — 2021-12-21
- 0.15.0 (beta) — 2019-09-27
- 3.0.1 — 2021-12-21
- 3.0.0 — 2021-12-21
- 2.0.1 — 2021-08-19
- 2.0.0 — 2021-04-08
- 1.0.0 — 2020-08-12
- 0.15.2 — 2020-02-02
- 0.15.1 — 2019-10-31
- 0.14.6 — 2019-07-23
- 0.14.5 — 2019-07-09
- 0.14.4 — 2019-01-11
- 0.14.3 — 2018-08-15
- 0.14.2 — 2018-04-30
- 0.14.1 — 2017-11-12
- … 25 more at https://npm.io/package/multistream-select/versions

## README

# js-multistream-select <!-- omit in toc -->

[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai)
[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats)
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs)
[![](https://img.shields.io/codecov/c/github/multiformats/js-multistream-select.svg?style=flat-square)](https://codecov.io/gh/multiformats/js-multistream-select)
[![](https://img.shields.io/travis/multiformats/js-multistream-select.svg?style=flat-square)](https://travis-ci.com/multiformats/js-multistream-select)
[![Dependency Status](https://david-dm.org/multiformats/js-multistream-select.svg?style=flat-square)](https://david-dm.org/multiformats/js-multistream-select)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)

> JavaScript implementation of [multistream-select](https://github.com/multiformats/multistream-select)

## Lead Maintainer <!-- omit in toc -->

[Jacob Heun](https://github.com/jacobheun)

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

- [Background](#background)
  - [What is `multistream-select`?](#what-is-multistream-select)
    - [Select a protocol flow](#select-a-protocol-flow)
- [Install](#install)
- [Usage](#usage)
  - [Dialer](#dialer)
  - [Listener](#listener)
- [API](#api)
  - [`new MSS.Dialer(duplex)`](#new-mssdialerduplex)
    - [Parameters](#parameters)
    - [Returns](#returns)
    - [Examples](#examples)
  - [`dialer.select(protocols, [options])`](#dialerselectprotocols-options)
    - [Parameters](#parameters-1)
    - [Returns](#returns-1)
    - [Examples](#examples-1)
  - [`dialer.ls([options])`](#dialerlsoptions)
    - [Parameters](#parameters-2)
    - [Returns](#returns-2)
    - [Examples](#examples-2)
  - [`new MSS.Listener(duplex)`](#new-msslistenerduplex)
    - [Parameters](#parameters-3)
    - [Returns](#returns-3)
    - [Examples](#examples-3)
  - [`listener.handle(protocols, [options])`](#listenerhandleprotocols-options)
    - [Parameters](#parameters-4)
    - [Returns](#returns-4)
    - [Examples](#examples-4)
- [Contribute](#contribute)
- [License](#license)

## Background

### What is `multistream-select`?

TLDR; multistream-select is protocol multiplexing per connection/stream. [Full spec here](https://github.com/multiformats/multistream-select)

#### Select a protocol flow

The caller will send "interactive" messages, expecting for some acknowledgement from the callee, which will "select" the handler for the desired and supported protocol:

```console
< /multistream-select/0.3.0  # i speak multistream-select/0.3.0
> /multistream-select/0.3.0  # ok, let's speak multistream-select/0.3.0
> /ipfs-dht/0.2.3            # i want to speak ipfs-dht/0.2.3
< na                         # ipfs-dht/0.2.3 is not available
> /ipfs-dht/0.1.9            # What about ipfs-dht/0.1.9 ?
< /ipfs-dht/0.1.9            # ok let's speak ipfs-dht/0.1.9 -- in a sense acts as an ACK
> <dht-message>
> <dht-message>
> <dht-message>
```

This mode also packs a `ls` option, so that the callee can list the protocols it currently supports

## Install

```sh
npm i multistream-select
```

## Usage

```js
const MSS = require('multistream-select')
// You can now use
// MSS.Dialer - actively select a protocol with a remote
// MSS.Listener - handle a protocol with a remote
```

### Dialer

```js
const pipe = require('it-pipe')
const MSS = require('multistream-select')
const Mplex = require('libp2p-mplex')

const muxer = new Mplex()
const muxedStream = muxer.newStream()

const mss = new MSS.Dialer(muxedStream)

// mss.select(protocol(s))
// Select from one of the passed protocols (in priority order)
// Returns selected stream and protocol
const { stream: dhtStream, protocol } = await mss.select([
  // This might just be different versions of DHT, but could be different impls
  '/ipfs-dht/2.0.0', // Most of the time this will probably just be one item.
  '/ipfs-dht/1.0.0'
])

// Typically this stream will be passed back to the caller of libp2p.dialProtocol
//
// ...it might then do something like this:
// try {
//   await pipe(
//     [uint8ArrayFromString('Some DHT data')]
//     dhtStream,
//     async source => {
//       for await (const chunk of source)
//         // DHT response data
//     }
//   )
// } catch (err) {
//   // Error in stream
// }
```

### Listener

```js
const pipe = require('it-pipe')
const MSS = require('multistream-select')
const Mplex = require('libp2p-mplex')

const muxer = new Mplex({
  async onStream (muxedStream) {
    const mss = new MSS.Listener(muxedStream)

    // mss.handle(handledProtocols)
    // Returns selected stream and protocol
    const { stream, protocol } = await mss.handle([
      '/ipfs-dht/1.0.0',
      '/ipfs-bitswap/1.0.0'
    ])

    // Typically here we'd call the handler function that was registered in
    // libp2p for the given protocol:
    // e.g. handlers[protocol].handler(stream)
    //
    // If protocol was /ipfs-dht/1.0.0 it might do something like this:
    // try {
    //   await pipe(
    //     dhtStream,
    //     source => (async function * () {
    //       for await (const chunk of source)
    //         // Incoming DHT data -> process and yield to respond
    //     })(),
    //     dhtStream
    //   )
    // } catch (err) {
    //   // Error in stream
    // }
  }
})
```

## API

### `new MSS.Dialer(duplex)`

Create a new multistream select "dialer" instance which can be used to negotiate a protocol to use, list all available protocols the remote supports, or do both.

#### Parameters

* `duplex` (`Object`) - A [duplex iterable stream](https://gist.github.com/alanshaw/591dc7dd54e4f99338a347ef568d6ee9#duplex-it) to dial on.

#### Returns

A new multistream select dialer instance.

#### Examples

```js
const dialer = new MSS.Dialer(duplex)
```

### `dialer.select(protocols, [options])`

Negotiate a protocol to use from a list of protocols.

#### Parameters

* `protocols` (`String[]`/`String`) - A list of protocols (or single protocol) to negotiate with. Protocols are attempted in order until a match is made.
* `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal

#### Returns

`Promise<{ stream<Object>, protocol<String> }>` - A stream for the selected protocol and the protocol that was selected from the list of protocols provided to `select`.

Note that after a protocol is selected `dialer` can no longer be used.

#### Examples

```js
const { stream, protocol } = await dialer.select([
  // This might just be different versions of DHT, but could be different impls
  '/ipfs-dht/2.0.0', // Most of the time this will probably just be one item.
  '/ipfs-dht/1.0.0'
])
// Now talk `protocol` on `stream`
```

### `dialer.ls([options])`

List protocols that the remote supports.

#### Parameters

* `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal

#### Returns

`String[]` - A list of all the protocols the remote supports.

#### Examples

```js
const protocols = await dialer.ls()
const wantedProto = '/ipfs-dht/2.0.0'

if (!protocols.includes(wantedProto)) {
  throw new Error('remote does not support ' + wantedProto)
}

// Now use dialer.select to use wantedProto, safe in the knowledge it is supported
```

### `new MSS.Listener(duplex)`

Construct a new multistream select "listener" instance which can be used to handle multistream protocol selections for particular protocols.

#### Parameters

* `duplex` (`Object`) - A [duplex iterable stream](https://gist.github.com/alanshaw/591dc7dd54e4f99338a347ef568d6ee9#duplex-it) to listen on.

#### Returns

A new multistream select listener instance.

#### Examples

```js
const listener = new MSS.Listener(duplex)
```

### `listener.handle(protocols, [options])`

Handle multistream protocol selections for the given list of protocols.

#### Parameters

* `protocols` (`String[]`/`String`) - A list of protocols (or single protocol) that this listener is able to speak.
* `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal

#### Returns

`Promise<{ stream<Object>, protocol<String> }>` - A stream for the selected protocol and the protocol that was selected from the list of protocols provided to `select`.

Note that after a protocol is handled `listener` can no longer be used.

#### Examples

```js
const { stream, protocol } = await listener.handle([
  '/ipfs-dht/1.0.0',
  '/ipfs-bitswap/1.0.0'
])
// Remote wants to speak `protocol`
```

## Contribute

Contributions welcome. Please check out [the issues](https://github.com/multiformats/js-multistream-select/issues).

Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).

Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.

## License

[MIT](LICENSE)

---
_Source: https://npm.io/package/multistream-select · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
