{"id":15153068,"url":"https://github.com/multiformats/js-multistream-select","last_synced_at":"2025-09-30T01:32:17.826Z","repository":{"id":33367776,"uuid":"37012649","full_name":"multiformats/js-multistream-select","owner":"multiformats","description":"JavaScript implementation of multistream-select","archived":true,"fork":false,"pushed_at":"2022-10-18T17:28:09.000Z","size":4649,"stargazers_count":29,"open_issues_count":10,"forks_count":18,"subscribers_count":18,"default_branch":"master","last_synced_at":"2024-09-24T00:35:58.784Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://github.com/multiformats/multistream","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/multiformats.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-06-07T10:34:47.000Z","updated_at":"2023-05-18T00:31:09.000Z","dependencies_parsed_at":"2022-07-31T10:48:08.193Z","dependency_job_id":null,"html_url":"https://github.com/multiformats/js-multistream-select","commit_stats":null,"previous_names":[],"tags_count":41,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/multiformats%2Fjs-multistream-select","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/multiformats%2Fjs-multistream-select/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/multiformats%2Fjs-multistream-select/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/multiformats%2Fjs-multistream-select/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/multiformats","download_url":"https://codeload.github.com/multiformats/js-multistream-select/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219874735,"owners_count":16554611,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-09-26T17:00:24.119Z","updated_at":"2025-09-30T01:32:17.524Z","avatar_url":"https://github.com/multiformats.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"⛔️ ARCHIVED: multistream-select can now be found at [@libp2p/multistream-select](https://github.com/libp2p/js-libp2p-multistream-select)\n=====\n\n# js-multistream-select \u003c!-- omit in toc --\u003e\n\n[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai)\n[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats)\n[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](https://webchat.freenode.net/?channels=%23ipfs)\n[![](https://img.shields.io/codecov/c/github/multiformats/js-multistream-select.svg?style=flat-square)](https://codecov.io/gh/multiformats/js-multistream-select)\n[![](https://img.shields.io/travis/multiformats/js-multistream-select.svg?style=flat-square)](https://travis-ci.com/multiformats/js-multistream-select)\n[![Dependency Status](https://david-dm.org/multiformats/js-multistream-select.svg?style=flat-square)](https://david-dm.org/multiformats/js-multistream-select)\n[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)\n\n\u003e JavaScript implementation of [multistream-select](https://github.com/multiformats/multistream-select)\n\n## Lead Maintainer \u003c!-- omit in toc --\u003e\n\n[Jacob Heun](https://github.com/jacobheun)\n\n## Table of Contents \u003c!-- omit in toc --\u003e\n\n- [Background](#background)\n  - [What is `multistream-select`?](#what-is-multistream-select)\n    - [Select a protocol flow](#select-a-protocol-flow)\n- [Install](#install)\n- [Usage](#usage)\n  - [Dialer](#dialer)\n  - [Listener](#listener)\n- [API](#api)\n  - [`new MSS.Dialer(duplex)`](#new-mssdialerduplex)\n    - [Parameters](#parameters)\n    - [Returns](#returns)\n    - [Examples](#examples)\n  - [`dialer.select(protocols, [options])`](#dialerselectprotocols-options)\n    - [Parameters](#parameters-1)\n    - [Returns](#returns-1)\n    - [Examples](#examples-1)\n  - [`dialer.ls([options])`](#dialerlsoptions)\n    - [Parameters](#parameters-2)\n    - [Returns](#returns-2)\n    - [Examples](#examples-2)\n  - [`new MSS.Listener(duplex)`](#new-msslistenerduplex)\n    - [Parameters](#parameters-3)\n    - [Returns](#returns-3)\n    - [Examples](#examples-3)\n  - [`listener.handle(protocols, [options])`](#listenerhandleprotocols-options)\n    - [Parameters](#parameters-4)\n    - [Returns](#returns-4)\n    - [Examples](#examples-4)\n- [Contribute](#contribute)\n- [License](#license)\n\n## Background\n\n### What is `multistream-select`?\n\nTLDR; multistream-select is protocol multiplexing per connection/stream. [Full spec here](https://github.com/multiformats/multistream-select)\n\n#### Select a protocol flow\n\nThe caller will send \"interactive\" messages, expecting for some acknowledgement from the callee, which will \"select\" the handler for the desired and supported protocol:\n\n```console\n\u003c /multistream-select/0.3.0  # i speak multistream-select/0.3.0\n\u003e /multistream-select/0.3.0  # ok, let's speak multistream-select/0.3.0\n\u003e /ipfs-dht/0.2.3            # i want to speak ipfs-dht/0.2.3\n\u003c na                         # ipfs-dht/0.2.3 is not available\n\u003e /ipfs-dht/0.1.9            # What about ipfs-dht/0.1.9 ?\n\u003c /ipfs-dht/0.1.9            # ok let's speak ipfs-dht/0.1.9 -- in a sense acts as an ACK\n\u003e \u003cdht-message\u003e\n\u003e \u003cdht-message\u003e\n\u003e \u003cdht-message\u003e\n```\n\nThis mode also packs a `ls` option, so that the callee can list the protocols it currently supports\n\n## Install\n\n```sh\nnpm i multistream-select\n```\n\n## Usage\n\n```js\nconst MSS = require('multistream-select')\n// You can now use\n// MSS.Dialer - actively select a protocol with a remote\n// MSS.Listener - handle a protocol with a remote\n```\n\n### Dialer\n\n```js\nconst pipe = require('it-pipe')\nconst MSS = require('multistream-select')\nconst Mplex = require('libp2p-mplex')\n\nconst muxer = new Mplex()\nconst muxedStream = muxer.newStream()\n\nconst mss = new MSS.Dialer(muxedStream)\n\n// mss.select(protocol(s))\n// Select from one of the passed protocols (in priority order)\n// Returns selected stream and protocol\nconst { stream: dhtStream, protocol } = await mss.select([\n  // This might just be different versions of DHT, but could be different impls\n  '/ipfs-dht/2.0.0', // Most of the time this will probably just be one item.\n  '/ipfs-dht/1.0.0'\n])\n\n// Typically this stream will be passed back to the caller of libp2p.dialProtocol\n//\n// ...it might then do something like this:\n// try {\n//   await pipe(\n//     [uint8ArrayFromString('Some DHT data')]\n//     dhtStream,\n//     async source =\u003e {\n//       for await (const chunk of source)\n//         // DHT response data\n//     }\n//   )\n// } catch (err) {\n//   // Error in stream\n// }\n```\n\n### Listener\n\n```js\nconst pipe = require('it-pipe')\nconst MSS = require('multistream-select')\nconst Mplex = require('libp2p-mplex')\n\nconst muxer = new Mplex({\n  async onStream (muxedStream) {\n    const mss = new MSS.Listener(muxedStream)\n\n    // mss.handle(handledProtocols)\n    // Returns selected stream and protocol\n    const { stream, protocol } = await mss.handle([\n      '/ipfs-dht/1.0.0',\n      '/ipfs-bitswap/1.0.0'\n    ])\n\n    // Typically here we'd call the handler function that was registered in\n    // libp2p for the given protocol:\n    // e.g. handlers[protocol].handler(stream)\n    //\n    // If protocol was /ipfs-dht/1.0.0 it might do something like this:\n    // try {\n    //   await pipe(\n    //     dhtStream,\n    //     source =\u003e (async function * () {\n    //       for await (const chunk of source)\n    //         // Incoming DHT data -\u003e process and yield to respond\n    //     })(),\n    //     dhtStream\n    //   )\n    // } catch (err) {\n    //   // Error in stream\n    // }\n  }\n})\n```\n\n## API\n\n### `new MSS.Dialer(duplex)`\n\nCreate 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.\n\n#### Parameters\n\n* `duplex` (`Object`) - A [duplex iterable stream](https://gist.github.com/alanshaw/591dc7dd54e4f99338a347ef568d6ee9#duplex-it) to dial on.\n\n#### Returns\n\nA new multistream select dialer instance.\n\n#### Examples\n\n```js\nconst dialer = new MSS.Dialer(duplex)\n```\n\n### `dialer.select(protocols, [options])`\n\nNegotiate a protocol to use from a list of protocols.\n\n#### Parameters\n\n* `protocols` (`String[]`/`String`) - A list of protocols (or single protocol) to negotiate with. Protocols are attempted in order until a match is made.\n* `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal\n\n#### Returns\n\n`Promise\u003c{ stream\u003cObject\u003e, protocol\u003cString\u003e }\u003e` - A stream for the selected protocol and the protocol that was selected from the list of protocols provided to `select`.\n\nNote that after a protocol is selected `dialer` can no longer be used.\n\n#### Examples\n\n```js\nconst { stream, protocol } = await dialer.select([\n  // This might just be different versions of DHT, but could be different impls\n  '/ipfs-dht/2.0.0', // Most of the time this will probably just be one item.\n  '/ipfs-dht/1.0.0'\n])\n// Now talk `protocol` on `stream`\n```\n\n### `dialer.ls([options])`\n\nList protocols that the remote supports.\n\n#### Parameters\n\n* `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal\n\n#### Returns\n\n`String[]` - A list of all the protocols the remote supports.\n\n#### Examples\n\n```js\nconst protocols = await dialer.ls()\nconst wantedProto = '/ipfs-dht/2.0.0'\n\nif (!protocols.includes(wantedProto)) {\n  throw new Error('remote does not support ' + wantedProto)\n}\n\n// Now use dialer.select to use wantedProto, safe in the knowledge it is supported\n```\n\n### `new MSS.Listener(duplex)`\n\nConstruct a new multistream select \"listener\" instance which can be used to handle multistream protocol selections for particular protocols.\n\n#### Parameters\n\n* `duplex` (`Object`) - A [duplex iterable stream](https://gist.github.com/alanshaw/591dc7dd54e4f99338a347ef568d6ee9#duplex-it) to listen on.\n\n#### Returns\n\nA new multistream select listener instance.\n\n#### Examples\n\n```js\nconst listener = new MSS.Listener(duplex)\n```\n\n### `listener.handle(protocols, [options])`\n\nHandle multistream protocol selections for the given list of protocols.\n\n#### Parameters\n\n* `protocols` (`String[]`/`String`) - A list of protocols (or single protocol) that this listener is able to speak.\n* `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal\n\n#### Returns\n\n`Promise\u003c{ stream\u003cObject\u003e, protocol\u003cString\u003e }\u003e` - A stream for the selected protocol and the protocol that was selected from the list of protocols provided to `select`.\n\nNote that after a protocol is handled `listener` can no longer be used.\n\n#### Examples\n\n```js\nconst { stream, protocol } = await listener.handle([\n  '/ipfs-dht/1.0.0',\n  '/ipfs-bitswap/1.0.0'\n])\n// Remote wants to speak `protocol`\n```\n\n## Contribute\n\nContributions welcome. Please check out [the issues](https://github.com/multiformats/js-multistream-select/issues).\n\nCheck 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).\n\nSmall note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmultiformats%2Fjs-multistream-select","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmultiformats%2Fjs-multistream-select","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmultiformats%2Fjs-multistream-select/lists"}