@nolag/chat

Multi-room chat with presence, typing indicators, message replay, and user mapping.

Overview

@nolag/chat is a high-level SDK that turns any application into a fully-featured chat system. It handles room management, user presence, typing indicators, message history replay, and unread tracking, all on top of @nolag/js-sdk. Your app owns one core NoLag client and injects it into NoLagChat; the wrapper attaches its chat behaviour to that connection. You create a NoLagChat instance, wait for it to be ready, join rooms, and start sending messages within minutes.

Key Features

  • Multi-room chat with isolated presence per room
  • Typing indicators with automatic timeout
  • Message replay to catch up on up to 7 days of history after reconnect
  • User mapping to attach names, avatars, and metadata to each actor
  • Unread message tracking with per-room badge counts
  • Automatic reconnection with state restoration

How It Works

NoLagChat attaches to an injected @nolag/js-sdk client and manages a lobby for global user presence. When you call joinRoom(), it returns a ChatRoom instance that subscribes to two topics: messages for durable chat history and _typing for ephemeral typing signals. A MessageStore inside each room accumulates messages and replayed history, while a PresenceManager tracks who is currently online. The app owns the socket lifecycle; the wrapper never opens or closes it.

TopicPurposeReplay
messagesChat messages: text, metadata, sender info7 days
_typingTyping start/stop signals (ephemeral)None

Installation

npm install @nolag/chat @nolag/js-sdk

One core NoLag client can back several wrapper SDKs at once, for example chat, notify, and a dashboard on a single socket, as long as each wrapper uses a distinct appName. Each wrapper attaches its handlers on construction and releases them with detach(), and never touches the socket itself. Your app owns connect() and disconnect().

Quick Start

import { NoLag } from '@nolag/js-sdk'
import { NoLagChat } from '@nolag/chat'

// The app owns one core client. In a browser, pass a token provider so the
// SDK can mint fresh short-lived client tokens from your backend.
const client = NoLag(async () => (await (await fetch('/api/nolag-token')).json()).token)

// Inject the client into the chat wrapper
const chat = new NoLagChat({ client, username: 'Alice', avatar: '/img/alice.png' })

await client.connect()   // the app owns the connection
await chat.ready()       // wrapper setup complete (identity, presence, rooms)

// Join a room
const room = chat.joinRoom('general')

// Send a message
room.sendMessage('Hello everyone!')

// Listen for messages
room.on('message', (msg) => {
  console.log(`[${msg.username}]: ${msg.text}`)
  console.log('Sent at:', new Date(msg.timestamp))
})

// Listen for typing indicators
room.on('typing', ({ users }) => {
  console.log('Typing:', users.map((u) => u.username).join(', '))
})

// Trigger typing events
room.startTyping()
// ... user stops typing
room.stopTyping()

// Get online users in this room
const users = room.getUsers()
console.log('Online:', users.length)

// Teardown: the wrapper releases its handlers and topics; the app closes the
// socket (never the other way around).
chat.detach()
client.disconnect()

API Reference

NoLagChat

The main class. Attaches to the injected core client, manages global user presence, and the room lifecycle.

Constructor Options

OptionTypeDescription
clientNoLagSocketRequired. The injected core NoLag client the app owns and connects.
usernamestringRequired. Display name for this user.
avatarstringOptional avatar URL.
metadataRecord<string, unknown>Optional custom user data attached to presence.
appNamestringNoLag app for topic prefixes (default 'chat').
roomsstring[]Rooms to auto-join once the wrapper is ready.
typingTimeoutnumberMs before a typing indicator auto-clears (default 3000).
maxMessageCachenumberMax messages kept in memory per room (default 500).
debugbooleanEnable wrapper debug logging (default false).
MethodDescription
ready()Resolves once wrapper setup completed (identity, lobby, configured rooms)
detach()Release this wrapper's handlers and topics; terminal, never closes the socket
joinRoom(name)Join a chat room; returns a ChatRoom instance
leaveRoom(name)Leave a room and unsubscribe from its topics
getOnlineUsers()Return all users currently online across all rooms
setStatus(status)Update your own presence status (e.g. 'away', 'busy')
updateProfile(profile)Update display name, avatar, or other profile fields broadcast to peers

Events: NoLagChat

EventPayloadDescription
connectednoneWebSocket connection established
disconnectedreason: stringConnection closed
reconnectednoneReconnection successful; rooms are restored automatically
errorerror: ErrorUnrecoverable error occurred
userOnlineuser: ChatUserA user has come online in the lobby
userOfflineuser: ChatUserA user has gone offline
userUpdateduser: ChatUserA user updated their profile or status

ChatRoom

Returned by joinRoom(). Scoped to a single room; handles messaging, typing, and per-room presence.

MethodDescription
sendMessage(text)Publish a chat message to the room
getMessages()Return all messages currently in the local store (including replayed history)
startTyping()Broadcast a typing-start signal to other room members
stopTyping()Broadcast a typing-stop signal
getUsers()Return users currently present in this room
markRead()Mark all messages in this room as read, resetting the unread count

Events: ChatRoom

EventPayloadDescription
messageChatMessageIncoming message from another user
messageSentChatMessageConfirmation that your own message was delivered
userJoinedChatUserA user joined this room
userLeftChatUserA user left this room
typing{ user: ChatUser, isTyping: boolean }A user started or stopped typing
replayStart{ count: number }Historical message replay is beginning
replayEnd{ replayed: number }Historical message replay is complete
unreadChanged{ count: number }The unread message count for this room changed