Hiyve Components - v1.0.0
    Preparing search index...

    Module @hiyve/semantic-relay-client

    @hiyve/semantic-relay-client — framework-agnostic browser client for the Hiyve Semantic Relay (Go WebTransport datagram service).

    Designed for high-frequency, fire-and-forget, room-scoped messaging where the WebRTC data channel's per-message overhead (negotiation, peer-to-peer routing, JSON snapshot envelopes) is too heavy. Typical use cases: instrument note events, semantic-avatar blendshape streams, spatial audio cues.

    For React applications, use @hiyve/react-semantic-relay which wraps this client with a context provider and topic-scoped pub/sub hooks.

    import { SemanticRelayClient } from '@hiyve/semantic-relay-client';

    const client = new SemanticRelayClient({
    url: 'https://semantic.hiyve.tv:4443/relay',
    roomId: 'lesson-abc',
    userId: 'alice@example.com',
    token: jwtFromBackend,
    serverCertificateHashes,
    });

    await client.connect();

    const unsubscribe = client.subscribe('instrument-notes', ({ payload, userId }) => {
    console.log(`${userId} played`, payload);
    });

    client.publish('instrument-notes', { midi: 60, on: true, velocity: 100 });
    // ...
    unsubscribe();
    client.dispose();

    @hiyve/semantic-relay-client

    Framework-agnostic browser client for the Hiyve Semantic Relay — built for high-frequency, fire-and-forget, room-scoped messaging.

    Connects over WebTransport (HTTP/3 / QUIC datagrams, preferred) with automatic WebSocket fallback: when WebTransport is missing or cannot connect (e.g. networks that block UDP), the client transparently retries over WebSocket against the same relay endpoint. Consumers use one API either way; the active transport is reported via client.transportKind.

    For React applications, use @hiyve/react-semantic-relay which wraps this client with a context provider and topic-scoped pub/sub hooks.

    npm install @hiyve/semantic-relay-client
    
    import { SemanticRelayClient } from '@hiyve/semantic-relay-client';

    const client = new SemanticRelayClient({
    url: 'https://semantic.hiyve.tv:4443/relay',
    roomId: 'lesson-abc',
    userId: 'alice@example.com',
    token: jwtFromBackend,
    serverCertificateHashes, // optional; required for self-signed dev/prod certs
    });

    const session = await client.connect();
    console.log('session id', session.sessionId, 'peers', session.peers);

    const unsubscribe = client.subscribe('instrument-notes', ({ payload, userId }) => {
    console.log(`${userId} played`, payload);
    });

    client.publish('instrument-notes', { midi: 60, on: true, velocity: 100 });

    // Later:
    unsubscribe();
    client.dispose();

    serverCertificateHashes is a RelayCertHash[] of SHA-256 fingerprints — see the WebTransport docs for derivation. Production deployments using a public CA can omit it.

    Option Required Description
    url yes Base WebTransport URL (https://...:4443/relay).
    roomId yes Room identifier — relay-side broadcast scope.
    userId yes Sender identity attached to every published message.
    token yes Short-lived auth token minted by the app backend.
    serverCertificateHashes no SHA-256 certificate hashes for self-signed certs.
    onError no Connection / publish / decode errors.
    onConnectionChange no Notification when the connection state changes (connecting, connected, closed, error).
    onDebug no Debug logger; pairs with createDebugLogger('hiyve:semantic-relay').
    maxSeenMessages no Per-topic dedupe cache size (default 200).
    pruneCount no Dedupe entries dropped when the cache is full (default 50).
    retryDelaysMs no Connect-retry backoff within a single connect() call (default [200, 800, 2000]). Auth failures bypass.
    reconnect no Keep the connection alive for the life of the room (default true). See Staying connected.
    reconnectBaseDelayMs no First reconnect delay, doubling to the cap (default 1000).
    reconnectMaxDelayMs no Ceiling for the reconnect delay (default 30000).
    getToken no Called before each reconnect attempt to supply a fresh token. Without it, a reconnect that fails authentication stops.
    transport no 'auto' (default), 'webtransport', or 'websocket'. In 'auto', WebTransport is tried first when available; any non-auth connect failure falls through to WebSocket.
    wsBufferedAmountHighWater no WebSocket congestion threshold in bytes (default 16 KB). While the socket is congested, outbound messages coalesce latest-wins per topic so fresh state is never queued behind stale state. Ignored on WebTransport.

    The client wraps relay messages in a small envelope; serialization, framing, and identity stamping are handled internally.

    A relay connection can be lost long after it was established — a VPN or tunnel dropping, a Wi-Fi handover, a laptop waking, the relay restarting. By default the client re-establishes it on its own, with a delay that doubles from reconnectBaseDelayMs to reconnectMaxDelayMs, and it keeps trying even when the very first connect() never succeeded, so a room joined on a network that blocks the relay recovers as soon as that network changes. Retries fire immediately when the browser reports the network is back or the tab becomes visible, rather than waiting out the remaining delay.

    Two things follow for consumers:

    • Re-read sessionInfo after a reconnect. The relay assigns a new session ID on rejoin, so the snapshot connect() resolved with is stale from the first drop onwards. onConnectionChange firing 'connected' again is the signal.
    • Subscriptions are not affected. They belong to the client, not the connection, so nothing needs re-registering.

    connect() still rejects when the first attempt fails — reconnection runs alongside that rejection rather than replacing it. Pass reconnect: false to connect once and stop.

    Tokens expire. If a lesson can outlive its token, supply getToken so each attempt presents a fresh one; without it, a reconnect rejected on authentication ends the loop, because retrying a token the relay has already refused achieves nothing. getToken is given the same 8s budget as a handshake — a token endpoint on the same broken network usually hangs rather than failing, and an unbounded wait there would stop the loop as surely as an error. Rejecting or timing out is not fatal: the next attempt asks again.

    • One sender per connection (peer routing is server-side).
    • Up to 100 participants per room (relay-enforced).
    • Max envelope size ~1200 bytes (MAX_DATAGRAM_BYTES); larger messages should fragment at the application layer.

    Every current browser is supported. WebTransport (the preferred transport) is available in Chrome/Edge 97+, Firefox 114+, and Safari 26.4+; everywhere else — including older Safari/iOS and networks that block UDP — the client falls back to WebSocket automatically. No consumer-side capability gating is required.

    Delivery semantics are fire-and-forget on both transports: messages may be dropped under network congestion (natively on WebTransport; via latest-wins coalescing on WebSocket), so protocols built on this client should tolerate loss — exactly as they must for datagrams.

    Export Description
    SemanticRelayClient The client class.
    RelayCertHash Shape of a single SHA-256 cert hash entry.
    RelayConnectionState 'idle' | 'connecting' | 'connected' | 'error' | 'closed'.
    RelayEnvelope<T> Wire envelope shape.
    RelayMessage<T> Subscriber-visible message: { topic, payload, userId, messageId, timestamp }.
    RelayOptions Constructor options shape.
    RelayTransportPolicy 'auto' | 'webtransport' | 'websocket'.
    RelayTransportKind 'webtransport' | 'websocket' — see client.transportKind.
    DEFAULT_RECONNECT_BASE_MS Default first reconnect delay (1000).
    DEFAULT_RECONNECT_MAX_MS Default reconnect delay ceiling (30000).
    RECONNECT_HEALTHY_MS How long a connection must last before a later drop restarts the backoff from the base delay (30000).
    DefaultedRelayOptions Options after defaults are applied.
    RelaySubscribeHandler<T> Callback signature for subscribe.
    SessionInfo Session metadata returned by connect().
    hasWebTransport() / hasWebSocket() Runtime capability probes.
    deriveWebSocketUrl(url) Maps the relay's https:// URL to its wss:// equivalent.
    DEFAULT_OPTIONS The full default options object.
    mergeOptions(user) Merge user options on top of DEFAULT_OPTIONS.
    MAX_DATAGRAM_BYTES Max envelope size (~1200).
    SESSION_ID_HEADER_BYTES Bytes reserved for the session-id header in each datagram.
    DEFAULT_MAX_SEEN_MESSAGES Default dedupe cache size.
    DEFAULT_PRUNE_COUNT Default prune count when the cache is full.
    DEFAULT_RETRY_DELAYS_MS Default reconnect backoff schedule.
    DEFAULT_CONNECT_TIMEOUT_MS Default connect timeout.
    DEFAULT_WS_BUFFERED_HIGH_WATER Default WebSocket congestion threshold (bytes).
    WS_FLUSH_INTERVAL_MS Congestion re-check cadence for coalesced sends.
    SESSION_INFO_TYPE Tag for SessionInfo messages on the control topic.

    MIT

    Classes

    SemanticRelayClient

    Interfaces

    DefaultedRelayOptions
    RelayCertHash
    RelayEnvelope
    RelayMessage
    RelayOptions
    SessionInfo

    Type Aliases

    RelayConnectionState
    RelaySubscribeHandler
    RelayTransportKind
    RelayTransportPolicy

    Variables

    DEFAULT_CONNECT_TIMEOUT_MS
    DEFAULT_MAX_SEEN_MESSAGES
    DEFAULT_OPTIONS
    DEFAULT_PRUNE_COUNT
    DEFAULT_RECONNECT_BASE_MS
    DEFAULT_RECONNECT_MAX_MS
    DEFAULT_RETRY_DELAYS_MS
    DEFAULT_WS_BUFFERED_HIGH_WATER
    MAX_DATAGRAM_BYTES
    RECONNECT_HEALTHY_MS
    SESSION_ID_HEADER_BYTES
    SESSION_INFO_TYPE
    WS_FLUSH_INTERVAL_MS

    Functions

    deriveWebSocketUrl
    hasWebSocket
    hasWebTransport
    mergeOptions