Chat SDK
Build private realtime chat rooms.
Use DomVia Realtime chat patterns for one-to-one rooms, group conversations, typing state, read receipts, presence, and optional private-message encryption.
Package
@domvia/realtime-chat
install
npm install @domvia/realtime @domvia/realtime-chat @domvia/realtime-server @domvia/realtime-e2ee
@domvia/realtime-chat
Built for focused realtime use cases.
Keep the SDK modular, documented, and safe to extend as new products are added.
Architecture
How this guide should be used.
Step 01
Use one protected room channel per conversation
Keep each conversation isolated. A good channel shape is private-chat.room.{roomId}. Your trusted server decides who can join before the client receives events.
Step 02
Keep the core client small
Use @domvia/realtime for the connection, then add @domvia/realtime-chat only where a product needs messaging helpers.
Step 03
Persist messages on your server
Realtime events should notify clients that something changed. Store durable message records, attachments, moderation flags, and audit history in your product database.
Step 04
Add E2EE only for private message content
Private chat content is the first E2EE target. Typing state, read receipts, and delivery status usually stay as normal protected events.
Examples
Focused implementation notes.
Client chat room
Connect with the public key, join a private chat room, listen for messages, and send throttled client typing signals when enabled.
Client chat room
import { DomViaRealtime } from "@domvia/realtime";
import {
buildChatChannelName,
createChatRoom,
} from "@domvia/realtime-chat";
const realtime = DomViaRealtime.create({
key: "pk_live_your_public_key",
host: "ws.domvia.net",
authEndpoint: "/realtime/auth",
clientEvents: true,
});
const room = createChatRoom(realtime, {
roomId: "room-42",
channelName: buildChatChannelName("room-42"),
encrypted: true,
});
await room.waitUntilReady();
room.onMessage((event) => {
console.log("New message:", event.message_id);
});
room.onTyping((event) => {
console.log("Typing:", event.user_id, event.is_typing);
});
room.sendTyping({
user_id: "user-1",
});Trusted server authorization
The browser never signs private channel access directly. Your server verifies the signed-in user and returns a signed authorization response.
Trusted server authorization
import { authorizePrivateChannel } from "@domvia/realtime-server";
app.post("/realtime/auth", async (request, response) => {
const user = await requireSignedInUser(request);
const channelName = request.body.channel_name;
const socketId = request.body.socket_id;
const roomId = channelName.replace("private-chat.room.", "");
if (!channelName.startsWith("private-chat.room.")) {
return response.status(403).json({ message: "Forbidden" });
}
if (!await userCanAccessChatRoom(user.id, roomId)) {
return response.status(403).json({ message: "Forbidden" });
}
return response.json(
await authorizePrivateChannel({
key: process.env.DOMVIA_REALTIME_KEY,
secret: process.env.DOMVIA_REALTIME_SECRET,
socketId,
channelName,
}),
);
});Safety
Rules before production traffic.
✓ Keep chat room membership checks on your trusted server.
✓ Never trust room IDs sent by the client without verifying membership.
✓ Use E2EE for private message content when the product requires participant-only readability.
✓ Do not put app secrets or room encryption keys in public client config.
✓ Keep attachments and durable message records in your product database.
Continue