@nolag/notify

Real-time notifications with channels, read/unread tracking, and badge counts.

Overview

@nolag/notify delivers real-time notifications to your users with full read/unread lifecycle management. Notifications are organised into channels (logical groupings like 'alerts', 'mentions', or 'system') and each channel tracks its own unread count independently. Your app owns one core NoLag client and injects it into NoLagNotify; the wrapper attaches its behaviour to that connection. The SDK replays up to 30 days of notification history on reconnect so users never miss an event regardless of when they were last online.

Key Features

  • Channel-based notification delivery with independent unread counts
  • 30-day notification replay so users catch up after any period offline
  • Per-notification and bulk read/unread tracking
  • Global badge counts aggregated across all subscribed channels
  • Rich notification payloads with title, body, icon, actions, and custom data
  • Automatic reconnection with channel restoration

How It Works

NoLagNotify attaches to an injected @nolag/js-sdk client. Each channel you subscribe to creates a NotifyChannel instance that subscribes to two topics: notifications for durable notification delivery and _read for ephemeral read-receipt signals. A NotificationStore inside each channel accumulates notifications and tracks read state, while the main class aggregates badge counts across all channels. The app owns the socket lifecycle; the wrapper never opens or closes it.

TopicPurposeReplay
notificationsNotification payloads: title, body, icon, actions, and custom data30 days
_readRead receipt signals (ephemeral)None

Installation

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

One core NoLag client can back several wrapper SDKs at once, for example notify, chat, 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 { NoLagNotify } from '@nolag/notify'

// 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 notify wrapper
const notify = new NoLagNotify({ client, metadata: { name: 'Alice' } })

await client.connect()   // the app owns the connection
await notify.ready()     // wrapper setup complete

// Subscribe to a notification channel
const channel = await notify.subscribe('alerts')

// Listen for new notifications
channel.on('notification', (n) => {
  console.log(`[${n.title}]: ${n.body}`)
  console.log('Unread:', channel.getUnread().length)
})

// Mark a specific notification as read
await channel.markRead(n.id)

// Mark everything in the channel as read
await channel.markAllRead()

// Get global badge counts across all channels
const badges = notify.getBadgeCounts()
console.log('Total unread:', badges.total)

// Mark all channels read at once
await notify.markAllRead()

// Teardown: the wrapper releases its handlers; the app closes the socket.
notify.detach()
client.disconnect()

API Reference

NoLagNotify

The main class. Attaches to the injected core client, manages channel subscriptions, and global badge counts.

Constructor Options

OptionTypeDescription
clientNoLagSocketRequired. The injected core NoLag client the app owns and connects.
metadataRecord<string, unknown>Optional custom user data attached to presence.
appNamestringNoLag app for topic prefixes (default 'notify').
channelsstring[]Channels to subscribe to once the wrapper is ready.
maxNotificationCachenumberMax notifications kept in memory per channel (default 500).
debugbooleanEnable wrapper debug logging (default false).
MethodDescription
ready()Resolves once wrapper setup completed
detach()Release this wrapper's handlers and topics; terminal, never closes the socket
subscribe(channel)Subscribe to a notification channel; returns a NotifyChannel instance
unsubscribe(channel)Unsubscribe from a channel and remove it from badge tracking
getBadgeCounts()Return unread counts for every subscribed channel plus a total aggregate
markAllRead()Mark all notifications across all subscribed channels as read

Events: NoLagNotify

EventPayloadDescription
connectednoneWebSocket connection established
disconnectedreason: stringConnection closed
reconnectednoneReconnection successful; channels are restored automatically
errorerror: ErrorUnrecoverable error occurred
notification{ channel: string, notification: Notification }A new notification arrived on any subscribed channel
badgeUpdated{ channel: string, count: number, total: number }Badge counts changed for a channel

NotifyChannel

Returned by subscribe(). Scoped to a single channel; handles notification delivery, storage, and read state.

MethodDescription
send(title, opts)Publish a notification to this channel (typically called server-side)
markRead(id)Mark a single notification as read by ID
markAllRead()Mark every notification in this channel as read
getNotifications()Return all notifications in the local store
getUnread()Return only unread notifications

Events: NotifyChannel

EventPayloadDescription
notificationNotificationA new notification arrived on this channel
read{ id: string }A notification was marked as read
readAllnoneAll notifications in this channel were marked as read
replayStart{ count: number }Historical notification replay is beginning
replayEnd{ replayed: number }Historical notification replay is complete