Skip to content

Quick Start

This guide walks you through building a simple real-time notification system.

Make sure you have:

  • Node.js 18+ or Bun
  • TypeScript configured in your project
  • PubSubJS packages installed (see Installation)

First, define the events your application will use:

events.ts
import { z } from "zod";
import { defineEvent } from "@pubsubjs/core";
export const events = defineEvent([
{
name: "notification.created",
schema: z.object({
id: z.string(),
userId: z.string(),
title: z.string(),
message: z.string(),
type: z.enum(["info", "warning", "error"]),
createdAt: z.string().datetime(),
}),
},
{
name: "notification.read",
schema: z.object({
id: z.string(),
userId: z.string(),
readAt: z.string().datetime(),
}),
},
]);
// TypeScript infers the event types automatically
export type Events = typeof events;

Choose a transport based on your use case. For this example, we’ll use WebSocket:

server.ts
import { WebSocketServerTransport } from "@pubsubjs/transport-websocket";
const transport = new WebSocketServerTransport({
port: 8080,
});
console.log("WebSocket server running on ws://localhost:8080");

Create a publisher to send events:

publisher.ts
import { Publisher } from "@pubsubjs/core";
import { events } from "./events";
export function createNotificationPublisher(transport) {
const publisher = new Publisher({
events,
transport,
});
return {
async sendNotification(userId: string, title: string, message: string, type: "info" | "warning" | "error") {
await publisher.publish("notification.created", {
id: crypto.randomUUID(),
userId,
title,
message,
type,
createdAt: new Date().toISOString(),
});
},
async markAsRead(id: string, userId: string) {
await publisher.publish("notification.read", {
id,
userId,
readAt: new Date().toISOString(),
});
},
};
}

Create a subscriber to receive events:

subscriber.ts
import { Subscriber } from "@pubsubjs/core";
import { events } from "./events";
export function createNotificationSubscriber(transport) {
const subscriber = new Subscriber({
events,
transport,
onError: (error, eventName, payload) => {
console.error(`Error handling ${eventName}:`, error);
},
});
subscriber.on("notification.created", (payload, { ctx }) => {
console.log(`[${ctx.messageId}] New notification for user ${payload.userId}:`);
console.log(` ${payload.type.toUpperCase()}: ${payload.title}`);
console.log(` ${payload.message}`);
});
subscriber.on("notification.read", (payload) => {
console.log(`Notification ${payload.id} marked as read by user ${payload.userId}`);
});
return subscriber;
}
main.ts
import { WebSocketServerTransport } from "@pubsubjs/transport-websocket";
import { events } from "./events";
import { createNotificationPublisher } from "./publisher";
import { createNotificationSubscriber } from "./subscriber";
async function main() {
// Create transport
const transport = new WebSocketServerTransport({ port: 8080 });
// Create publisher and subscriber
const notifications = createNotificationPublisher(transport);
const subscriber = createNotificationSubscriber(transport);
// Start subscribing
await subscriber.subscribe();
console.log("Notification system ready!");
// Send a test notification
await notifications.sendNotification(
"user-123",
"Welcome!",
"Thanks for trying PubSubJS",
"info"
);
// Mark it as read after 2 seconds
setTimeout(async () => {
await notifications.markAsRead("notif-1", "user-123");
}, 2000);
}
main().catch(console.error);
Terminal window
bun main.ts

You should see:

WebSocket server running on ws://localhost:8080
Notification system ready!
[abc123] New notification for user user-123:
INFO: Welcome!
Thanks for trying PubSubJS
Notification notif-1 marked as read by user user-123

Enhance your subscriber with middleware:

import {
Subscriber,
createSubscriberLoggingMiddleware,
createRateLimitMiddleware,
} from "@pubsubjs/core";
const subscriber = new Subscriber({
events,
transport,
middleware: [
createSubscriberLoggingMiddleware(),
createRateLimitMiddleware({
maxEvents: 100,
windowMs: 1000,
onLimit: (eventName) => {
console.warn(`Rate limit exceeded for ${eventName}`);
},
}),
],
});