# protomux

> Multiplex multiple message oriented protocols over a stream

Latest version **3.12.0** (published 2026-09-09) · MIT license · 0 weekly downloads

## Install

```sh
npm install protomux
pnpm add protomux
yarn add protomux
bun add protomux
```

## Health

**Score 60/100 (C)** — status: active.

Positive: no vulnerabilities; has provenance; recently updated; high maintenance score.

Warnings: low downloads; no types; no esm support.

## Facts

| | |
|---|---|
| Version | 3.12.0 |
| Published | 2026-09-09 |
| First published | 2021-12-30 |
| Weekly downloads | 0 |
| License | MIT |
| TypeScript types | none |
| Module format | CommonJS |
| Dependencies | 5 |
| Unpacked size | 25.7 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Provenance | attested (GitHub Actions) |
| GitHub stars | 45 |
| Author | Mathias Buus |
| Maintainers | mafintosh |

## Links

- npm: https://www.npmjs.com/package/protomux
- Repository: https://github.com/holepunchto/protomux
- Issues: https://github.com/holepunchto/protomux/issues
- npm.io page: https://npm.io/package/protomux

## Dependencies (5)

- [b4a](https://npm.io/package/b4a.md) ^1.3.1
- [unslab](https://npm.io/package/unslab.md) ^1.3.0
- [queue-tick](https://npm.io/package/queue-tick.md) ^1.0.0
- [safety-catch](https://npm.io/package/safety-catch.md) ^1.0.1
- [compact-encoding](https://npm.io/package/compact-encoding.md) ^3.0.0

## Recent versions

- 3.12.0 (latest) — 2026-09-09
- 3.11.0 — 2026-05-05
- 3.10.3 — 2026-04-21
- 3.10.1 — 2024-12-31
- 3.10.0 — 2024-10-02
- 3.9.2 — 2024-07-30
- 3.9.1 — 2024-07-23
- 3.9.0 — 2024-07-16
- 3.8.1 — 2024-05-30
- 3.8.0 — 2024-05-29
- 3.7.0 — 2024-05-29
- 3.6.0 — 2024-05-01
- 3.5.2 — 2024-04-19
- 3.5.1 — 2023-08-21
- 3.5.0 — 2023-06-26
- … 15 more at https://npm.io/package/protomux/versions

## README

# protomux

Multiplex multiple message oriented protocols over a stream

```
npm install protomux
```

## Usage

```js
const Protomux = require('protomux')
const c = require('compact-encoding')

// By framed stream, it has be a stream that preserves the messages, ie something that length prefixes
// like @hyperswarm/secret-stream

const mux = new Protomux(aStreamThatFrames)

// Now add some protocol channels

const cool = mux.createChannel({
  protocol: 'cool-protocol',
  id: Buffer.from('optional binary id'),
  onopen() {
    console.log('the other side opened this protocol!')
  },
  onclose() {
    console.log('either side closed the protocol')
  }
})

// And add some messages

const one = cool.addMessage({
  encoding: c.string,
  onmessage(m) {
    console.log('recv message (1)', m)
  }
})

const two = cool.addMessage({
  encoding: c.bool,
  onmessage(m) {
    console.log('recv message (2)', m)
  }
})

// open the channel

cool.open()

// And send some data

one.send('a string')
two.send(true)
```

## API

#### `mux = new Protomux(stream, [options])`

Make a new instance. `stream` should be a framed stream, preserving the messages written.

Options include:

```js
{
  // Called when the muxer wants to allocate a message that is written, defaults to Buffer.allocUnsafe.
  alloc (size) {}
}
```

#### `mux = Protomux.from(stream | muxer, [options])`

Helper to accept either an existing muxer instance or a stream (which creates a new one).

#### `const channel = mux.createChannel(opts)`

Add a new protocol channel.

Options include:

```js
{
  // Used to match the protocol
  protocol: 'name of the protocol',
  // Optional additional binary id to identify this channel
  id: buffer,
  // Optional encoding for a handshake
  handshake: encoding,
  // Optional array of messages types you want to send/receive.
  messages: [],
  // Called when the remote side adds this protocol.
  // Errors here are caught and forwared to stream.destroy
  async onopen (handshake) {},
  // Called when the channel closes - ie the remote side closes or rejects this protocol or we closed it.
  // Errors here are caught and forwared to stream.destroy
  async onclose () {},
  // Called after onclose when all pending promises has resolved.
  async ondestroy () {}
}
```

Sessions are paired based on a queue, so the first remote channel with the same `protocol` and `id`.

**NOTE**: `mux.createChannel` returns `null` if the channel should not be opened, ie it's a duplicate channel or the remote has already closed this one.

If you want multiple sessions with the same `protocol` and `id`, set `unique: false` as an option.

#### `const opened = mux.opened({ protocol, id })`

Boolean that indicates if the channel is opened.

#### `mux.pair({ protocol, id }, callback)`

Register a callback to be called everytime a new channel is requested.

#### `mux.unpair({ protocol, id })`

Unregisters the pair callback.

#### `channel.open([handshake])`

Open the channel.

#### `const m = channel.addMessage(opts)`

Add/register a message type for a certain encoding. Options include:

```js
{
  // compact-encoding specifying how to encode/decode this message
  encoding: c.binary,
  // Called when the remote side sends a message.
  // Errors here are caught and forwared to stream.destroy,
  // unless the channel has already closed, in which case the stream
  // is left alone but the error is emitted via the `warning` event
  async onmessage (message) { }
}
```

#### `m.send(data)`

Send a message.

#### `m.onmessage`

Function that is called when a message arrives.

#### `m.encoding`

The encoding for this message.

#### `channel.close()`

Closes the protocol channel.

#### `channel.cork()`

Corking the protocol channel, makes it buffer messages and send them all in a batch when it uncorks.

#### `channel.uncork()`

Uncork and send the batch.

#### `mux.cork()`

Same as `channel.cork` but on the muxer instance.

#### `mux.uncork()`

Same as `channel.uncork` but on the muxer instance.

#### `for (const channel of muxer) { ... }`

The muxer instance is iterable, so you can iterate over all the channels.

#### `mux.isIdle()`

Convenience method that returns true if the number of channels is currently 0.

## License

MIT

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