Skip to main content

API Reference

Both classes are exported from @kynesyslabs/demosdk under the instantMessaging namespace:
import { instantMessaging } from "@kynesyslabs/demosdk"

const { L2PSMessagingPeer, MessagingPeer } = instantMessaging
There is no @kynesyslabs/demosdk/instant_messaging subpath — the package root is the only canonical entry point.

L2PSMessagingPeer

The production client. Connects to the L2PS messaging server (default port 3006) and provides registered, E2E-encrypted, persisted messaging with pagination, offline delivery, and L2PS pipeline tracking.

Constructor

constructor(config: L2PSMessagingConfig)
interface L2PSMessagingConfig {
    /** WebSocket URL of the L2PS messaging server (e.g. "ws://localhost:3006") */
    serverUrl: string
    /** Client's ed25519 public key (hex string, 64+ chars) */
    publicKey: string
    /** L2PS network UID to join */
    l2psUid: string
    /** Function to sign proof strings with ed25519 private key. Returns hex signature. */
    signFn: (message: string) => Promise<string> | string
}
signFn is invoked by the SDK whenever a frame requires an ed25519 proof — currently for register (register:{publicKey}:{timestamp}) and history (history:{peerKey}:{timestamp}). It must return a hex-encoded ed25519 signature of the input string. Example:
const peer = new L2PSMessagingPeer({
    serverUrl: "ws://your-demos-node:3006",
    publicKey: myEd25519PublicKeyHex,
    l2psUid: "your-l2ps-network-uid",
    signFn: async (msg) => myEd25519.signHex(msg),
})

Lifecycle

connect()

async connect(): Promise<RegisteredResponse["payload"]>
// payload: { success: boolean, publicKey: string, l2psUid: string, onlinePeers: string[] }
Opens the WebSocket, sends register with a fresh ed25519 proof, and resolves once the server replies with the registered frame. Times out after 10 seconds. The returned payload includes the list of currently online peers in the same L2PS network.

disconnect()

disconnect(): void
Stops automatic reconnection, closes the WebSocket, rejects all pending request-response promises with Disconnected, clears the local peer set, and notifies connection-state handlers with "disconnected".

Messaging

send(to, encrypted, messageHash)

async send(
    to: string,
    encrypted: SerializedEncryptedMessage,
    messageHash: string,
): Promise<MessageSentResponse["payload"] | MessageQueuedResponse["payload"]>
Sends an already-encrypted message to a peer. The returned payload is one of:
  • { messageHash, l2psStatus: "submitted" | "failed" } — server frame message_sent
  • { messageHash, status: "queued" } — server frame message_queued (recipient was offline)
Throws Not registered. Call connect() first. if invoked before connect() completes.

history(peerKey, options)

async history(
    peerKey: string,
    options: { before?: number; limit?: number } = {},
): Promise<HistoryResponse["payload"]>
// payload: { messages: StoredMessage[], hasMore: boolean }
Fetches conversation history with peerKey. before is a millisecond timestamp for backward pagination; limit caps the page size. The SDK signs history:{peerKey}:{timestamp} with signFn and includes the proof in the request.

discover()

async discover(): Promise<string[]>
Returns the list of online peer public keys in the current L2PS network. Also updates the internal peer set (readable via peer.peers).

requestPublicKey(targetId)

async requestPublicKey(targetId: string): Promise<string | null>
Looks up a peer’s public key by identifier. Returns the hex string, or null if the server cannot resolve targetId.

Getters

GetterTypeMeaning
isConnectedbooleanWebSocket open.
isRegisteredbooleanServer accepted the register frame.
peersstring[]Snapshot of currently online peer public keys.

Event handlers

All on* handlers can be registered multiple times; registration order is preserved.
type L2PSMessageHandler = (message: IncomingMessage["payload"]) => void
type L2PSErrorHandler = (error: ErrorResponse["payload"]) => void
type L2PSPeerHandler = (publicKey: string) => void
type L2PSConnectionStateHandler = (state: "connected" | "disconnected" | "reconnecting") => void
MethodFires when
onMessage(handler)Server delivers a message frame. Handler receives { from, encrypted, messageHash, offline? }.
onError(handler)Server sends an error frame, or a local protocol error occurs. Handler receives { code, message, details? }.
onPeerJoined(handler)A peer joined the L2PS network (peer_joined frame).
onPeerLeft(handler)A peer left the L2PS network (peer_left frame).
onConnectionStateChange(handler)WebSocket transitions between "connected", "disconnected", and "reconnecting".
Removal counterparts:
peer.removeMessageHandler(handler)
peer.removeErrorHandler(handler)
peer.removePeerJoinedHandler(handler)
peer.removePeerLeftHandler(handler)
peer.removeConnectionStateHandler(handler)

Reconnection

On unexpected socket close, L2PSMessagingPeer retries with exponential backoff:
  • Base delay 1000 ms, doubled per attempt.
  • Capped at 30 000 ms.
  • Up to 10 attempts.
  • After the socket re-opens, register is replayed automatically; pending send/history/discover requests are not replayed.

MessagingPeer (legacy)

The legacy signaling-server client (default port 3005). Provides peer registration, discovery, and per-message relay with the same ml-kem-aes encryption applied client-side. No persistence, no history API, no offline queue, no server-side delivery acknowledgement.

Constructor

constructor(config: MessagingPeerConfig)

interface MessagingPeerConfig {
    serverUrl: string
    clientId: string
    publicKey: Uint8Array
}
Example:
const peer = new instantMessaging.MessagingPeer({
    serverUrl: "ws://your-signaling-server:3005",
    clientId: "your-unique-id",
    publicKey: mlKemAes.publicKey,
})

Methods

MethodSignatureDescription
connectasync connect(): Promise<void>Connect and register.
disconnectdisconnect(): voidClose the WebSocket.
registerregister(): voidSend the register frame (no wait).
registerAndWaitasync registerAndWait(): Promise<void>Register and await confirmation; signs the public key with ml-dsa for binding.
discoverPeersasync discoverPeers(): Promise<string[]>Returns the list of connected peer client IDs.
sendMessageasync sendMessage(targetId: string, message: string): Promise<void>Encrypts message with the recipient’s public key (auto-fetched) and relays through the signaling server.
requestPublicKeyasync requestPublicKey(peerId: string): Promise<Uint8Array>Returns the peer’s public key bytes.
respondToServerrespondToServer(questionId: string, response: any): voidReplies to a server_question with a peer_response.
sendToServerAndWaitasync sendToServerAndWait<T>(message: Message, expectedResponseType: Message["type"], options?: { timeout?: number; errorHandler?: (e: any) => void; retryCount?: number; filterFn?: (m: Message) => boolean }): Promise<T>Generic request-response helper with optional retry, timeout, custom error handling, and message filtering.

Event handlers

MethodHandler signature
onMessage(handler)(message: any, fromId: string) => void
onError(handler)(error: { type: string; details: string }) => void
onPeerDisconnected(handler)(peerId: string) => void
onConnectionStateChange(handler)(state: "connected" | "disconnected" | "reconnecting") => void
onServerQuestion(handler)(question: any, questionId: string) => void
Removal counterparts: removeMessageHandler, removeErrorHandler, removePeerDisconnectedHandler, removeConnectionStateHandler.

Message interface

interface Message {
    type:
        | "register"
        | "discover"
        | "message"
        | "peer_disconnected"
        | "request_public_key"
        | "public_key_response"
        | "server_question"
        | "peer_response"
        | "debug_question"
        | "error"
    payload: any
}

Reconnection

Same shape as L2PSMessagingPeer: exponential backoff starting at 1000 ms, capped at 30 000 ms, up to 10 attempts. Queued outbound messages are flushed once the connection reopens.