ReferenceHelpers
Secretstream
Noise-encrypted duplex stream used for Holepunch peer transports.
stable
Secretstream wraps a transport stream in a Noise handshake plus libsodium secretstream encryption. It is the encrypted stream layer used underneath Hyperswarm and related peer transports. For the upstream package, source, and release notes, see the @hyperswarm/secret-stream repository.
Install
npm i @hyperswarm/secret-streamQuickstart
import SecretStream from '@hyperswarm/secret-stream'
const a = new SecretStream(true)
const b = new SecretStream(false)
a.rawStream.pipe(b.rawStream).pipe(a.rawStream)
a.write(Buffer.from('hello encrypted world'))
b.on('data', (data) => {
console.log(data.toString())
})API Reference
Constructor and lifecycle
const stream = new SecretStream(isInitiator, [rawStream], [options])
- Signature:
const stream = new SecretStream(isInitiator, [rawStream], [options])(GitHub) - Parameters:
isInitiatoristruefor the dialing side andfalsefor the accepting side.rawStreamis an optional underlying transport stream.options.patternoverrides the Noise pattern,remotePublicKeypins the remote identity when the pattern requires it,keyPairprovides a local key pair or a promise resolving to one,handshakeinjects an already-computed handshake,enableSenddisables unordered UDP-style sends when set tofalse,keepAliveconfigures heartbeat writes, andautoStartdefaults totrue. (GitHub) - Returns: A duplex encrypted stream. You can use it like a normal stream for ordered reads and writes once the handshake completes. (GitHub)
- Example:
const socket = getTransportSocketSomehow()
const stream = new SecretStream(true, socket, {
keepAlive: 10_000
})stream.start([rawStream], [options])
- Signature:
stream.start([rawStream], [options])(GitHub) - Parameters:
rawStreamis the transport to wrap whenautoStart: falsewas used.optionsaccepts the same handshake-related fields as the constructor, includingkeyPair,handshake,data, andended. (GitHub) - Returns: Nothing. It wires the transport, starts the handshake, and begins pumping encrypted data. (GitHub)
- Example:
const stream = new SecretStream(true, null, { autoStart: false })
stream.start(socket, { remotePublicKey })await stream.flush()
- Signature:
await stream.flush()(GitHub) - Parameters: None. (GitHub)
- Returns: A promise resolving to
truewhen pending encrypted writes and the underlying raw stream have flushed successfully, orfalseif the stream closed before that happened. (GitHub) - Example:
stream.write(Buffer.from('hello'))
await stream.flush()Stream configuration
stream.setTimeout(ms)
- Signature:
stream.setTimeout(ms)(GitHub) - Parameters:
msis the idle timeout in milliseconds. Use0to disable the timeout. (GitHub) - Returns: Nothing. When the timer expires without inbound data, the stream destroys itself with a timeout error. (GitHub)
- Example:
stream.setTimeout(30_000)stream.setKeepAlive(ms)
- Signature:
stream.setKeepAlive(ms)(GitHub) - Parameters:
msis the heartbeat interval in milliseconds. Use0to disable keepalives. (GitHub) - Returns: Nothing. The stream will periodically send empty encrypted frames while idle. (GitHub)
- Example:
stream.setKeepAlive(10_000)stream.sendKeepAlive()
- Signature:
stream.sendKeepAlive()(GitHub) - Parameters: None. (GitHub)
- Returns: Nothing. Immediately writes one empty encrypted keepalive frame. (GitHub)
- Example:
stream.sendKeepAlive()Ordered stream I/O
stream.write(buffer)
- Signature:
stream.write(buffer)(GitHub) - Parameters:
bufferis the ordered payload to encrypt and send through the duplex stream. (GitHub) - Returns: The usual writable-stream backpressure boolean. (GitHub)
- Example:
stream.write(Buffer.from('ordered payload'))stream.end([buffer])
- Signature:
stream.end([buffer])(GitHub) - Parameters:
bufferis an optional final ordered payload. (GitHub) - Returns: The stream instance, following standard writable-stream behavior. (GitHub)
- Example:
stream.end(Buffer.from('goodbye'))stream.on('data', listener)
- Signature:
stream.on('data', listener)(GitHub) - Parameters:
listenerreceives ordered decrypted payloads asBufferinstances. (GitHub) - Returns: The stream itself. (GitHub)
- Example:
stream.on('data', (data) => {
console.log(data.toString())
})Unordered messages
await stream.send(buffer)
- Signature:
await stream.send(buffer)(GitHub) - Parameters:
bufferis the unordered datagram payload to encrypt. (GitHub) - Returns: A promise when the underlying raw stream supports
send(...)semantics, orundefinedwhen unordered sending is unavailable. Messages sent before handshake completion are silently dropped. (GitHub) - Example:
await stream.opened
await stream.send(Buffer.from('unordered ping'))stream.trySend(buffer)
- Signature:
stream.trySend(buffer)(GitHub) - Parameters:
bufferis the unordered datagram payload to encrypt. (GitHub) - Returns: Nothing. It attempts a best-effort unordered send when the underlying transport supports
trySend(...). (GitHub) - Example:
stream.trySend(Buffer.from('fire-and-forget'))stream.on('message', listener)
- Signature:
stream.on('message', listener)(GitHub) - Parameters:
listenerreceives decrypted unordered messages asBufferinstances. (GitHub) - Returns: The stream itself. (GitHub)
- Example:
stream.on('message', (message) => {
console.log(message.toString())
})Utility methods
const buffer = stream.alloc(length)
- Signature:
const buffer = stream.alloc(length)(GitHub) - Parameters:
lengthis the ordered payload size you want to write next. (GitHub) - Returns: A writable payload slice backed by a preallocated encrypted output buffer. Write into it, then pass it to
stream.write(...). (GitHub) - Example:
const payload = stream.alloc(5)
payload.set(Buffer.from('hello'))
stream.write(payload)const json = stream.toJSON()
- Signature:
const json = stream.toJSON()(GitHub) - Parameters: None. (GitHub)
- Returns: A diagnostic object containing connection state, keys, and any serializable raw-stream metadata. (GitHub)
- Example:
console.log(stream.toJSON())Static helpers
const keyPair = SecretStream.keyPair([seed])
- Signature:
const keyPair = SecretStream.keyPair([seed])(GitHub) - Parameters:
seedis an optional 32-byte seed for deterministic key generation. (GitHub) - Returns: An ed25519
{ publicKey, secretKey }pair suitable for the Noise handshake. (GitHub) - Example:
const keyPair = SecretStream.keyPair()const id = SecretStream.id(handshakeHash, isInitiator, [out])
- Signature:
const id = SecretStream.id(handshakeHash, isInitiator, [out])(GitHub) - Parameters:
handshakeHashis the completed handshake hash,isInitiatorchooses the initiator/responder namespace, andoutoptionally supplies an output buffer. (GitHub) - Returns: A 32-byte stream identity derived from the handshake. (GitHub)
- Example:
await stream.opened
const id = SecretStream.id(stream.handshakeHash, stream.isInitiator)Public properties
stream.isInitiator
- Returns:
trueon the dialing side andfalseon the accepting side. (GitHub)
stream.rawStream
- Returns: The wrapped transport stream, or a bridge stream when no raw stream was supplied up front. (GitHub)
stream.publicKey
- Returns: The local public key used in the handshake. (GitHub)
stream.remotePublicKey
- Returns: The remote peer's public key after the handshake succeeds. (GitHub)
stream.handshakeHash
- Returns: The Noise handshake hash after the encrypted session is established. (GitHub)
stream.connected
- Returns:
trueonce the handshake is complete and the stream has emittedconnect. (GitHub)
stream.keepAlive
- Returns: The configured keepalive interval in milliseconds. (GitHub)
stream.timeout
- Returns: The configured idle-timeout interval in milliseconds. (GitHub)
stream.enableSend
- Returns:
truewhen unorderedsend(...)andtrySend(...)support is enabled. (GitHub)
stream.opened
- Returns: A promise that resolves to
truewhen the handshake succeeds, orfalseif the stream closes before opening. (GitHub)
stream.rawBytesWritten
- Returns: The total encrypted byte count written to the raw stream. (GitHub)
stream.rawBytesRead
- Returns: The total encrypted byte count read from the raw stream before decryption. (GitHub)
stream.userData
- Returns: An arbitrary user-controlled field that higher-level protocols often use to attach transport metadata. (GitHub)
Events
stream.on('connect', listener)
- Signature:
stream.on('connect', listener)(GitHub) - Parameters:
listenerfires once the handshake is complete and ordered writes are fully active. (GitHub) - Returns: The stream itself. (GitHub)
- Example:
stream.on('connect', () => {
console.log(stream.remotePublicKey)
})stream.on('handshake', listener)
- Signature:
stream.on('handshake', listener)(GitHub) - Parameters:
listenerfires when the Noise handshake keys and hash have been established. (GitHub) - Returns: The stream itself. (GitHub)
- Example:
stream.on('handshake', () => {
console.log(stream.handshakeHash)
})See also
- Hyperswarm — the peer-discovery and connection layer that typically hands sockets to Secretstream.
- HyperDHT — lower-level DHT whose direct keyed connections are also wrapped in Secretstream.
- Protomux — multiplex higher-level protocols across one framed encrypted stream.
- Upstream @hyperswarm/secret-stream repository — source, releases, and implementation details.