@hyperfrontend/network-protocol/browser/channel

channel

Browser-side channel factories pre-wired with the browser sender and receiver implementations.

Overview

A channel is a named, bidirectional, queue-backed conduit that binds one protocol instance to one negotiated session. This entry point composes the runtime-agnostic channel logic from lib/channel with the browser sender (/browser/sender) and receiver (/browser/receiver), so createChannel needs a label and an options object: the transport callbacks, a ProtocolProvider from /browser/v3 or /browser/v4, the ProtocolSession, and an optional onDrop handler. The channel exposes the protocol's hello exchange (hello, isHello, acceptHello) so the session can be keyed over the same transport.

Usage

import { createChannel, createChannelStore } from '@hyperfrontend/network-protocol/browser/channel'
import { createProtocol } from '@hyperfrontend/network-protocol/browser/v3'
import { createLogger } from '@hyperfrontend/logging'

const channel = createChannel('app-to-widget', {
  send: (frame) => otherWindow.postMessage(frame, origin, [frame.buffer]),
  receive: (packet) => handle(packet.data.message),
  protocolProvider: createProtocol(createLogger({ level: 'info' })),
  session: { protocol: 'v3', role: 'initiator', localId, peerId },
  onDrop: (drop) => report(drop),
})
otherWindow.postMessage(await channel.hello(), origin)
window.addEventListener('message', ({ data }) => (channel.isHello(data) ? channel.acceptHello(data) : channel.receive(data)))

const store = createChannelStore()
store.add(channel)

Notes

API Reference§

ƒ Functions

§function

getFirstInvalidProtocolProperty(protocol: unknown): string

Identifies the first invalid property in a protocol object.

Parameters

NameTypeDescription
§protocol
unknown
The protocol object to inspect

Returns

string
The name of the first property that is not a function, or an empty string when every property is valid

Example

Reporting a protocol missing its opener

getFirstInvalidProtocolProperty({ seal, send, receive, getLogger })
// => 'open'
§function

isValidChannel(channel: unknown): boolean

Checks that a value has the shape of a channel: send, receive, and hello-exchange functions and an outbound and inbound pipeline each exposing a queue with a size and stop/resume controls.

Parameters

NameTypeDescription
§channel
unknown
The value to check

Returns

boolean
True when the value has the shape of a Channel

Example

Guarding a channel before storing it

isValidChannel(createChannel('comms', options))
// => true
§function

isValidLabel(label: string): boolean

Validates whether a label meets the required criteria of being a non-empty string.

Parameters

NameTypeDescription
§label
string
The label string to validate

Returns

boolean
True if the label is valid, false otherwise

Example

Validating channel labels

isValidLabel('channel-1') // => true
isValidLabel('') // => false
§function

isValidReceiver(receiver: unknown): boolean

Validates whether a receiver meets the required criteria of being a function.

Parameters

NameTypeDescription
§receiver
unknown
The receiver to validate

Returns

boolean
True if the receiver is valid, false otherwise

Example

Validating receiver functions

isValidReceiver((packet) => handlePacket(packet)) // => true
isValidReceiver('not-a-function') // => false
§function

isValidSender(sender: unknown): boolean

Validates whether a sender meets the required criteria of being a function.

Parameters

NameTypeDescription
§sender
unknown
The sender to validate

Returns

boolean
True if the sender is valid, false otherwise

Example

Validating sender functions

isValidSender((packet) => transmit(packet)) // => true
isValidSender(null) // => false
§function

isValidSession(session: unknown): unknown

Checks that a value has the shape of a protocol session: a protocol id, a role, and both identities.

Parameters

NameTypeDescription
§session
unknown
The value to check

Returns

unknown
True when the value has the shape of a ProtocolSession

Example

Guarding a session before binding a protocol to it

isValidSession({ protocol: 'v3', role: 'initiator', localId, peerId })
// => true

Interfaces

§interface

Channel

Secure communication channel with an outbound and an inbound pipeline

Properties

§readonly inbound:InboundPipeline
Inbound pipeline
§readonly label:string
Channel label for identification
§readonly outbound:OutboundPipeline
Outbound pipeline
§readonly receive:ReceiveFn
Receives sealed frames from the channel; hello frames go to acceptHello instead
§resume:() => void
Resumes the operation
§readonly send:SendFn<T>
Sends a message through the channel
§stop:() => void
Stops the operation
§interface

ChannelEntry

Entry in a channel store with metadata

Properties

§readonly channel:Channel<T>
The channel instance
§readonly id:string
Unique channel identifier
§readonly name:string
Channel name
§interface

ChannelOptions

Everything a channel needs beyond its label

Properties

§readonly onDrop?:PacketDropHandler
Optional; receives every packet either pipeline discards
§readonly protocolProvider:ProtocolProvider<T>
Creates the protocol instance for the session
§readonly receive:ReceivePacketFn<T>
Receives each opened packet
§readonly send:SendPacketFn
Transmits each sealed frame to the peer
§readonly session:ProtocolSession
The negotiated session the protocol instance is bound to
§interface

ChannelStore

Store for managing multiple channels

Properties

§readonly add:(topic: Channel<T>[]) => void
Adds channels to the store
§readonly clear:() => void
Removes all channels
§readonly create:(label: string, options: ChannelOptions<T>) => Channel<T>
Creates and returns a new channel
§readonly existsById:(id: string) => boolean
Checks if a channel exists by ID
§readonly existsByName:(name: string) => boolean
Checks if a channel exists by name
§readonly getById:(id: string) => Channel<T>
Gets a channel by ID
§readonly getByName:(name: string) => Channel<T>
Gets a channel by name
§readonly list:unknown
List of all channel entries
§readonly removeById:(id: string[]) => void
Removes channels by ID
§readonly removeByName:(name: string[]) => void
Removes channels by name
§interface

HelloExchange

The hello exchange that keys a session: each side sends its public material in the clear and accepts the peer's before any frame can be sealed or opened.

Properties

§interface

InboundPipeline

The inbound side of a channel: its open queue and its controls

Properties

§readonly queue:InboundQueue
The frames waiting to be opened
§resume:() => void
Resumes the operation
§stop:() => void
Stops the operation
§interface

OutboundPipeline

The outbound side of a channel: its seal queue and its controls

Properties

§readonly queue:OutboundQueue
The packets waiting to be sealed
§resume:() => void
Resumes the operation
§stop:() => void
Stops the operation
§interface

PacketDrop

A packet a pipeline stage rejected and the pipeline discarded

Properties

§readonly cause?:unknown
The error the stage threw, when it threw one
§readonly direction:"inbound" | "outbound"
Whether the packet was leaving (outbound) or arriving (inbound)
§readonly packet:unknown
The packet as the stage received it
§readonly reason:string
Why the stage rejected it
§readonly stage:PacketDropStage
The stage that rejected the packet
§interface

Protocol

Protocol instance: the session's seal and open operations, its hello exchange, and the transport callbacks

Properties

§getLogger:() => Logger
Returns the logger instance
§open:PacketOpener<T>
Opens incoming frames under the session's receiving key
§receive:ReceivePacketFn<T>
Receives an opened packet
§seal:PacketSealer<T>
Seals outgoing packets under the session's sending key
§send:SendPacketFn
Transmits a sealed frame
§interface

ProtocolSession

What a protocol needs to key one session: the negotiated protocol, this side's role, and both identities. The key material itself is minted by the protocol and exchanged through hello frames once the session exists.

Properties

§readonly localId:string
This endpoint's identity as stamped on packets
§readonly peerId:string
The peer's identity as stamped on packets
§readonly protocol:string
The negotiated protocol identifier
§readonly role:SessionRole
Whether this endpoint initiated or answered the handshake
§interface

StopResumeControl

Interface for stopping and resuming operations

Properties

§resume:() => void
Resumes the operation
§stop:() => void
Stops the operation

Types

§type

ChannelCreater

Factory function for creating channels
type ChannelCreater = (label: string, options: ChannelOptions<T>) => Channel<T>
§type

HelloOutcome

What accepting a hello frame did.
  • accepted: the peer's material is now known and the session can be keyed
  • duplicate: the same material was already accepted; a retry, ignored
  • rejected: the frame is not a hello this session can use
type HelloOutcome = "accepted" | "duplicate" | "rejected"
§type

PacketDropHandler

Receives each packet a pipeline discards
type PacketDropHandler = (drop: PacketDrop) => void
§type

PacketDropStage

The pipeline stage that rejected a packet
type PacketDropStage = "seal" | "open"
§type

ProtocolProvider

Factory function that creates a protocol instance for one session from send/receive functions
type ProtocolProvider = (send: SendPacketFn, receive: ReceivePacketFn<T>, session: ProtocolSession) => Protocol<T>
§type

SessionRole

Which side of the handshake this endpoint played
type SessionRole = "initiator" | "responder"

Variables

§type

createChannel

§type

createChannelStore