Skip to content

client.message

See the Messaging guide for usage. All methods require a configured app key (websockets are ticket-authorized) and a signed-in user: publish and send throw client.message: not signed in before sign-in.

interface MuhkooMessageEvent<T = unknown> {
subject: string;
from: string;
data: T;
}
interface MessageSubscription {
subject: string;
unsubscribe(): void;
}
subscribe<T>(subject: string, handler: (e: MuhkooMessageEvent<T>) => void): MessageSubscription

Subscribe to a pub/sub subject, or to your own user:<id> to receive direct messages. Returns a handle with .unsubscribe().

publish<T>(subject: string, data: T): Promise<void>

Plaintext fan-out to everyone subscribed to subject. Not encrypted: the platform and every subscriber can read it.

send<T>(target: string, payload: T): Promise<void>

End-to-end-encrypted direct message. target must be user:<id>; throws otherwise. Delivered in the recipient’s inbox space — they must be subscribed and online. The payload is JSON-encoded before encryption; the recipient’s handler gets it parsed back (a non-JSON string is passed through as is).

disconnect(): void

Closes every open connection (e.g. on logout).

A room is a low-level handle on a shared space — the same Space class client.space returns (Room is its older name), but opened without a group keyring. It gives you connect(), raw frames, the pairwise Double Ratchet send(text), and room-scoped file storage (putFile / getFile, which work without connecting). Fan-out group messaging (sendMessage, history, …) throws on a room: open the space through client.space for that.

const roomId = await client.message.createRoom(); // mint a private room id
const room = client.message.room(roomId); // open a handle

createRoom() mints the id server-side, and that is not incidental: the id is a 64-hex string that encodes which kind of platform object it addresses, which the accelerator validates on every later request. A client-generated id is rejected.

room(id) opens a handle without connecting — the websocket is not opened until you actually use it, so constructing handles is cheap.

For group channels with names, roles and invite links, prefer client.space.

For group messaging with persisted history and space-scoped file sharing, use client.space channels (createChannel / joinChannel), which add a name registry, history, and keeper-admitted membership.