Live notifications
Live notifications: subscribe to a named topic and receive messages in real time from any other connected client; publish a message and every subscriber gets it immediately. Topics are ephemeral — messages are not stored and are delivered only to currently connected subscribers.
Push notifications
"User X is typing", "New alert!", live score updates.
Signaling
WebRTC offer/answer exchange, presence heartbeats, coordination.
Ephemeral events
Cursor positions, typing indicators, game state bursts.
Subscribe to a topic (React)
Use the useTopic hook. It manages the subscription lifecycle — subscribes on mount, unsubscribes on unmount. The hook returns a TopicHandle so you can publish from the same component.
import { useTopic } from '@topgunbuild/react';
import { useState } from 'react';
interface ChatMessage {
userId: string;
text: string;
}
export function ChatLog({ roomId }: { roomId: string }) {
const [messages, setMessages] = useState<ChatMessage[]>([]);
// Subscribe: callback fires on every incoming message
useTopic(`chat:${roomId}`, (msg) => {
setMessages(prev => [...prev, msg as ChatMessage]);
});
return (
<ul>
{messages.map((m, i) => (
<li key={i}><strong>{m.userId}:</strong> {m.text}</li>
))}
</ul>
);
} Publish to a topic (React)
useTopic returns a TopicHandle. Call .publish(payload) to send a message to all subscribers of that topic.
import { useTopic } from '@topgunbuild/react';
import { useState } from 'react';
interface ChatMessage {
userId: string;
text: string;
}
export function ChatInput({ roomId, userId }: { roomId: string; userId: string }) {
const [text, setText] = useState('');
// Subscribe and get a handle for publishing
const topic = useTopic(`chat:${roomId}`);
const send = () => {
if (!text.trim()) return;
topic.publish({ userId, text } satisfies ChatMessage);
setText('');
};
return (
<div>
<input
value={text}
onChange={(e) => setText(e.target.value)}
onKeyDown={(e) => e.key === 'Enter' && send()}
placeholder="Type a message..."
/>
<button onClick={send}>Send</button>
</div>
);
} Non-React contexts
In Node.js services, service workers, or integration tests, use the imperative client.topic(name) API directly. The TopicHandle returned by client.topic() is the same object useTopic wraps.
import { TopGunClient } from '@topgunbuild/client';
import { IDBAdapter } from '@topgunbuild/adapters';
const client = new TopGunClient({
serverUrl: 'ws://localhost:8080',
storage: new IDBAdapter(),
});
await client.start();
const chatTopic = client.topic('chat:room-general');
// Subscribe
const unsubscribe = chatTopic.subscribe((data, context) => {
console.log('Received:', data);
// context.publisherId — sender's nodeId (undefined if sent from server)
// context.timestamp — HLC timestamp of the message
console.log('From:', context.publisherId, 'At:', new Date(context.timestamp));
});
// Publish
chatTopic.publish({ userId: 'alice', text: 'Hello from Node.js!' });
// Stop listening when done
unsubscribe(); Topic ordering and delivery
| Property | Behaviour |
|---|---|
| Delivery guarantee | At-most-once. Messages are not ACKed or persisted. |
| Offline behaviour | If a subscriber is offline when a message is published, they do not receive it on reconnect. Use getMap() or getORMap() for durable history. |
| Re-subscription | The client automatically re-subscribes to all active topics on reconnect to the server. |
| Ordering | Messages from a single publisher arrive in send order. Cross-publisher ordering is not guaranteed. |
| Payload type | Any JSON-serialisable value: string, number, object, array. |
When to use topics vs maps
Use topics for transient events where delivery to currently-offline users is not required (typing indicators, cursor positions, live scores). Use maps (via useQuery / getMap) for durable data that must survive disconnects and page reloads.
Next steps
- Real-time collaboration — combine topics with shared maps for cursors + document edits
- Offline-first apps — understand how map-backed data survives disconnects
- Client API reference — full
topic(name)andTopicHandlemethod signatures