Protomux
Multiplex multiple framed protocols over one transport stream.
v3.11.0Protomux multiplexes multiple message-oriented subprotocols over one framed stream. It is typically layered on top of NoiseSecretStream and uses compact-encoding for message schemas. For source and releases, see the Protomux repository.
Install
npm i protomuxQuickstart
import Protomux from 'protomux'
import cenc from 'compact-encoding'
const mux = new Protomux(aFramedEncryptedStream)
const channel = mux.createChannel({
protocol: 'chat',
onopen() {
console.log('chat channel opened')
}
})
const message = channel.addMessage({
encoding: cenc.string,
onmessage(text) {
console.log(text)
}
})
channel.open()
message.send('hello')API Reference
Constructor and mux helpers
mux = new Protomux(stream, [options])
Make a new instance. stream should be a framed stream, preserving the messages written.
| Parameter | Type | Default | Description |
|---|---|---|---|
stream | object | — | — |
options | ProtomuxOptions | {} | Optional configuration for the instance, such as a custom buffer allocator. |
{
// Called when the muxer wants to allocate a message that is written.
// Defaults to the stream's own alloc method when it has one, otherwise 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).
| Parameter | Type | Description |
|---|---|---|
stream | object | A framed stream or an existing Protomux instance. |
opts | ProtomuxOptions | Muxer options passed through when a new instance is created. |
- Returns:
Protomux— The existing or newly created Protomux instance.
const mux = Protomux.from(someStream)Protomux.isProtomux(mux)
Returns true when value looks like a Protomux instance.
| Parameter | Type | Description |
|---|---|---|
mux | object | Value to test. |
- Returns:
boolean—truewhenmuxis a Protomux instance.
Protomux.isProtomux(mux) // true
Protomux.isProtomux({}) // falsemux.cork()
Same as channel.cork but on the muxer instance.
- Returns:
void
mux.cork()
channelA.messages[0].send('hello')
channelB.messages[0].send('world')
mux.uncork() // sends both as one framemux.uncork()
Same as channel.uncork but on the muxer instance.
- Returns:
void
mux.cork()
msg.send('hello')
mux.uncork()mux.isIdle()
Convenience method that returns true when no channels are open and no closed channel is still awaiting the remote's acknowledgement.
- Returns:
boolean—truewhen the muxer has no open channels and none awaiting a remote close acknowledgement.
if (mux.isIdle()) console.log('no open channels')for (const channel of muxer) { ... }
The muxer instance is iterable, so you can iterate over all the channels.
Pairing and channel discovery
mux.pair({ protocol, id }, callback)
Register a callback to be called everytime a new channel is requested.
| Parameter | Type | Description |
|---|---|---|
options | ChannelKey | Protocol name and optional binary id to match. |
notify | Function | Async callback called with the channel's binary id when a matching remote channel opens. |
- Returns:
void
mux.pair({ protocol: 'my-protocol' }, async (id) => {
const channel = mux.createChannel({ protocol: 'my-protocol' })
channel.open()
})mux.unpair({ protocol, id })
Unregisters the pair callback.
| Parameter | Type | Description |
|---|---|---|
options | ChannelKey | Protocol name and optional binary id to deregister. |
- Returns:
void
mux.unpair({ protocol: 'my-protocol' })mux.opened({ protocol, id })
Boolean that indicates if the channel is opened.
| Parameter | Type | Description |
|---|---|---|
options | ChannelKey | Protocol name and optional binary id to check. |
- Returns:
boolean—truewhen one or more matching channels are open.
if (mux.opened({ protocol: 'my-protocol' })) {
console.log('already open')
}mux.getLastChannel(options)
Returns the channel that most recently opened. Returns null once that channel closes, even if older channels with the same protocol and id are still open.
| Parameter | Type | Description |
|---|---|---|
options | ChannelKey | Protocol name and optional binary id. |
- Returns:
Channel\|null— The most recently opened matching channel, ornull.
const ch = mux.getLastChannel({ protocol: 'my-protocol' })Creating channels
mux.createChannel(opts)
Add a new protocol channel.
| Parameter | Type | Description |
|---|---|---|
opts | CreateChannelOptions | Channel creation options. |
- Returns:
Channel\|null— The new channel, ornullif it cannot be opened.
Mux properties
mux.stream
The framed transport stream backing this mux.
- Returns:
object
mux.drained
The current writable backpressure state from the underlying stream.
- Returns:
boolean
Channel lifecycle
channel.open([handshake])
Open the channel.
| Parameter | Type | Description |
|---|---|---|
handshake | * | Optional handshake value encoded with the handshake encoding provided to createChannel. |
- Returns:
void
const channel = mux.createChannel({ protocol: 'my-protocol' })
channel.open()channel.fullyOpened()
Resolves to true when the channel fully opens or false if it closes first.
- Returns:
Promise<boolean>
const opened = await channel.fullyOpened()
if (opened) console.log('channel is open')channel.fullyClosed()
Resolves once the channel has been destroyed and all pending async handlers have finished.
- Returns:
Promise<void>
await channel.fullyClosed()
console.log('channel destroyed')channel.close()
Closes the protocol channel.
- Returns:
void
channel.close()channel.cork()
Corking the protocol channel, makes it buffer messages and send them all in a batch when it uncorks.
- Returns:
void
channel.cork()
one.send('hello')
two.send(true)
channel.uncork() // sends both as a single batchchannel.uncork()
Uncork and send the batch.
- Returns:
void
channel.cork()
one.send('hello')
channel.uncork()Registering and sending messages
channel.addMessage(opts)
Add/register a message type for a certain encoding. Options include:
| Parameter | Type | Description |
|---|---|---|
opts | AddMessageOptions | Message options including encoding and onmessage handler. |
- Returns:
object— Message object with asend(data)method for sending encoded messages.
m.send(data)
Send a message.
m.encoding
The encoding for this message.
m.onmessage
Function that is called when a message arrives.
Channel properties
channel.userData
- Returns: The arbitrary metadata value passed to
mux.createChannel(...).
channel.protocol
- Returns: The channel protocol name.
channel.aliases
- Returns: The list of alternate protocol names registered for this channel family.
channel.id
- Returns: The optional binary identifier distinguishing this channel family.
channel.handshake
- Returns: The decoded handshake payload after the channel fully opens, or
nullwhen no handshake encoder was configured.
channel.messages
- Returns: The array of registered message descriptors in type order.
channel.opened
channel.closed
- Returns:
trueafter either side closes the channel.
channel.destroyed
- Returns:
trueafter the close lifecycle and pending handlers have fully drained.
channel.drained
true when the underlying stream's write buffer is empty.
- Returns:
boolean
Lifecycle callbacks
channel.onopen
- Returns: Called when the channel opens.
handshakeis the decoded open payload ornull, andchannelis the channel instance.
channel.onclose
- Returns: Called when the channel closes.
isRemoteistruewhen the remote side initiated the close, andchannelis the channel instance.
channel.ondestroy
- Returns: Called when the channel is destroyed.
channelis the destroyed channel instance.
channel.ondrain
- Returns: Called when the channel's underlying mux becomes writable again.
channelis that channel instance.
Types
ProtomuxOptions
Options for allocating buffers in a Protomux instance.
| Property | Type | Default | Description |
|---|---|---|---|
alloc | Function | — | Custom allocator; called with (size) and must return a Buffer. Defaults to the stream's own alloc method when it has one, otherwise Buffer.allocUnsafe. |
CreateChannelOptions
Options for creating a protocol channel.
| Property | Type | Default | Description |
|---|---|---|---|
protocol | string | — | Protocol name used to match channels between peers. |
id | Buffer|null | null | Optional binary identifier to distinguish multiple channels with the same protocol name. |
handshake | * | null | compact-encoding codec for encoding/decoding the handshake value exchanged on open. |
messages | Array<AddMessageOptions> | [] | Array of message descriptors registered when the channel is created. |
unique | boolean | true | When true, returns null if a channel with this protocol+id is already open. |
aliases | Array<string> | [] | Alternative protocol names that also match this channel. |
userData | * | null | Arbitrary value stored as channel.userData; not transmitted. |
onopen | Function | — | Called with (handshake, channel) when the remote side opens this protocol. |
onclose | Function | — | Called with (isRemote, channel) when either side closes the channel. |
ondestroy | Function | — | Called with (channel) after onclose resolves and all pending promises settle. |
ondrain | Function | — | Called with (channel) when the underlying stream drains. |
AddMessageOptions
Options for registering a message type on a channel.
| Property | Type | Default | Description |
|---|---|---|---|
encoding | object | — | A compact-encoding codec. Defaults to raw binary (c.raw). |
autoBatch | boolean | true | When true, batch replies are collected before the next tick. |
onmessage | Function | — | Called with (message, channel) when the remote sends a message of this type. |
ChannelKey
Protocol + id selector used by pair/unpair/opened/getLastChannel.
| Property | Type | Default | Description |
|---|---|---|---|
protocol | string | — | Protocol name to match. |
id | Buffer|null | null | Optional binary id, combined with protocol into an exact key. opened and getLastChannel only match channels created with the same id; a protocol-only pair registration matches channels with any id. |
See also
- NoiseSecretStream—the encrypted framed stream most commonly used underneath Protomux.
- compact-encoding—the schema toolkit Protomux uses for handshakes and message payloads.
- Hyperswarm—common peer-transport entry point before you layer on NoiseSecretStream and Protomux.
- Upstream Protomux repository—source, releases, and implementation details.