@nolag/feed
Activity feeds with posts, likes, comments, and fan-out delivery.
Overview
@nolag/feed powers real-time activity feeds for social apps, community platforms, and content aggregators. Posts, likes, and comments are delivered live to all subscribers of a channel and replayed for up to 30 days so users joining late always see a full timeline. Fan-out happens server-side: publish once to a channel and every subscriber receives the update instantly.
Key Features
- Real-time post, like, and comment delivery to all channel subscribers
- 30-day replay across all three topics: posts, reactions, and comments
- Unread post tracking with per-channel badge counts
- Unlike support with live tally updates
- Nested comment threads per post
- Automatic reconnection with channel and state restoration
How It Works
NoLagFeed wraps the @nolag/js-sdk client. Calling joinChannel() creates a FeedChannel that subscribes to three topics: posts for post creation events, reactions for like and unlike events, and comments for comment creation events. A PostStore accumulates posts and their reaction counts, while a CommentStore groups comments by post ID. An unread counter tracks posts that arrived while the user was away.
| Topic | Purpose | Replay |
|---|---|---|
posts | Post creation events: text, media, author, timestamp | 30 days |
reactions | Like and unlike events with running tally | 30 days |
comments | Comment creation events keyed by post ID | 30 days |
Installation
npm install @nolag/feed @nolag/js-sdkQuick Start
import { NoLagFeed } from '@nolag/feed'
// Create and connect the client
const feed = new NoLagFeed('your-access-token', {
user: { id: 'user-123', name: 'Alice', avatar: '/img/alice.png' },
})
await feed.connect()
// Join a feed channel (e.g. a user timeline or community feed)
const channel = await feed.joinChannel('user-123-timeline')
// Listen for new posts in real time
channel.on('postCreated', (post) => {
console.log(`${post.author.name}: ${post.text}`)
console.log('Likes:', post.likeCount)
})
// Create a post
await channel.createPost({
text: 'Just shipped a new feature!',
media: [{ type: 'image', url: '/uploads/screenshot.png' }],
})
// Like a post
await channel.likePost('post-abc')
channel.on('postLiked', ({ postId, likeCount }) => {
console.log(`Post ${postId} now has ${likeCount} likes`)
})
// Comment on a post
await channel.addComment('post-abc', 'Congrats!')
channel.on('commentAdded', ({ postId, comment }) => {
console.log(`New comment on ${postId}: ${comment.text}`)
})
// Get unread count and mark as read
console.log('Unread:', channel.unreadCount)
await channel.markRead()
await feed.leaveChannel('user-123-timeline')
feed.disconnect()API Reference
NoLagFeed
The main class. Manages the WebSocket connection, global user presence, and feed channel lifecycle.
| Method | Description |
|---|---|
connect() | Establish WebSocket connection and announce presence |
disconnect() | Gracefully close the connection and leave all channels |
joinChannel(name) | Join a feed channel; returns a FeedChannel instance |
leaveChannel(name) | Leave a channel and unsubscribe from its topics |
getOnlineUsers() | Return all users currently online across all joined channels |
Events: NoLagFeed
| Event | Payload | Description |
|---|---|---|
connected | none | WebSocket connection established |
disconnected | reason: string | Connection closed |
reconnected | none | Reconnection successful; channels are restored automatically |
error | error: Error | Unrecoverable error occurred |
userOnline | user: FeedUser | A user has come online |
userOffline | user: FeedUser | A user has gone offline |
FeedChannel
Returned by joinChannel(). Handles posts, reactions, comments, and unread tracking for a single channel.
| Method / Property | Description |
|---|---|
createPost(opts) | Publish a new post with text, optional media array, and custom metadata |
likePost(postId) | Like a post; increments the like count for all subscribers |
unlikePost(postId) | Remove your like from a post |
addComment(postId, text) | Add a comment to the specified post |
getPosts() | Return all posts in the local store, newest first |
getComments(postId) | Return all comments for the specified post |
unreadCount | Number of posts that arrived since markRead() was last called |
markRead() | Reset the unread count to zero |
Events: FeedChannel
| Event | Payload | Description |
|---|---|---|
postCreated | FeedPost | A new post arrived from another user |
postSent | FeedPost | Confirmation that your own post was delivered |
postLiked | { postId: string, likeCount: number, likedBy: string } | A post received a new like |
postUnliked | { postId: string, likeCount: number, unlikedBy: string } | A like was removed from a post |
commentAdded | { postId: string, comment: FeedComment } | A comment was added to a post |
commentSent | { postId: string, comment: FeedComment } | Confirmation that your own comment was delivered |
subscriberJoined | user: FeedUser | A user joined this channel |
subscriberLeft | user: FeedUser | A user left this channel |
replayStart | { count: number } | Historical feed replay is beginning |
replayEnd | { replayed: number } | Historical feed replay is complete |
unreadChanged | { count: number } | The unread post count for this channel changed |