payload-websocket
v1.0.0
Published
WebSocket manager for Payload CMS with authentication, rooms, and real-time broadcasting
Maintainers
Readme
payload-websocket
WebSocket manager for Payload CMS with authentication, rooms, and real-time broadcasting - Socket.io style API.
✨ Features
- 🔐 Mandatory Authentication with Payload CMS
- 🏠 Rooms (Socket.io style)
- 📡 Broadcasting to users, rooms, or all clients
- 🔌 Multiple connections per user
- 📘 Full TypeScript support
- 🎯 Easy integration with Payload hooks
- ⚡ Zero dependencies (uses peer dependencies)
📦 Installation
npm install payload-websocket
# or
pnpm add payload-websocket
# or
yarn add payload-websocketPeer Dependencies
Make sure you have these installed:
npm install next next-ws payload ws
npm install -D @types/wsConfigure next.config.mjs
import { withPayload } from '@payloadcms/next/withPayload'
import nextWebSocket from 'next-ws/server'
/** @type {import('next').NextConfig} */
const nextConfig = {
// ... your config
}
// Apply next-ws FIRST, then Payload
export default nextWebSocket(withPayload(nextConfig))🚀 Quick Start
1. Create WebSocket Route
Create src/app/api/ws/route.ts:
import { createWebSocketRoute } from 'payload-websocket'
import configPromise from '@payload-config'
const { GET, UPGRADE } = createWebSocketRoute({
payloadConfig: configPromise,
})
export { GET, UPGRADE }That's it! You now have a fully functional WebSocket server with authentication.
🔐 Authentication
All WebSocket connections require authentication. Three methods supported:
1. Cookie (Automatic in Admin Panel)
const ws = new WebSocket('ws://localhost:3000/api/ws')
// Uses payload-token cookie automatically2. Query Parameter
const ws = new WebSocket(`ws://localhost:3000/api/ws?token=${token}`)3. Authorization Header
const ws = new WebSocket('ws://localhost:3000/api/ws', {
headers: {
Authorization: `Bearer ${token}`
}
})📨 Client Messages
Join a Room
ws.send(JSON.stringify({
type: 'join',
room: 'room-name'
}))Leave a Room
ws.send(JSON.stringify({
type: 'leave',
room: 'room-name'
}))Send Message to Room
ws.send(JSON.stringify({
type: 'message',
room: 'room-name',
event: 'my-event',
data: { message: 'Hello!' }
}))Broadcast to All
ws.send(JSON.stringify({
type: 'broadcast',
event: 'announcement',
data: { text: 'Important update!' }
}))Get Connection Stats
ws.send(JSON.stringify({ type: 'stats' }))🎯 Server-side Broadcasting
In Payload Hooks
import { broadcastToRoom, broadcastToUser } from 'payload-websocket'
export const Tasks: CollectionConfig = {
slug: 'tasks',
fields: [
{ name: 'title', type: 'text' },
{ name: 'completed', type: 'checkbox' },
],
hooks: {
afterChange: [
async ({ doc, operation }) => {
// Broadcast to all users in the 'tasks' room
broadcastToRoom('tasks', 'task:changed', {
id: doc.id,
title: doc.title,
completed: doc.completed,
operation, // 'create' or 'update'
})
return doc
},
],
},
}Available Broadcasting Functions
import {
broadcastToUser, // Send to specific user (all their connections)
broadcastToRoom, // Send to all in a room
broadcastToAllUsers, // Send to everyone
emitToSocket, // Send to specific socket
} from 'payload-websocket'
// Examples:
broadcastToUser('user-id', 'notification', { message: 'Hello!' })
broadcastToRoom('chat-room', 'new-message', { text: 'Hi there!' })
broadcastToAllUsers('announcement', { text: 'Server maintenance soon' })⚙️ Advanced Configuration
Custom Message Handler
import { createWebSocketRoute } from 'payload-websocket'
import configPromise from '@payload-config'
const { GET, UPGRADE } = createWebSocketRoute({
payloadConfig: configPromise,
// Custom message handler
onMessage: async (client, message, userId) => {
console.log(`User ${userId} sent:`, message)
if (message.type === 'custom-action') {
// Your custom logic
client.send(JSON.stringify({
event: 'custom-response',
data: { success: true }
}))
}
},
// Custom connection handler
onConnect: async (client, userId) => {
console.log(`User ${userId} connected`)
// Auto-join user to their personal room
joinRoom(client, `user:${userId}`)
},
// Custom disconnect handler
onDisconnect: async (userId, code, reason) => {
console.log(`User ${userId} disconnected: ${reason}`)
},
// Custom cookie name
cookieName: 'my-custom-token',
})
export { GET, UPGRADE }🎨 Frontend Example (React)
'use client'
import { useEffect, useState, useRef } from 'react'
export default function RealtimeTasks() {
const [tasks, setTasks] = useState([])
const ws = useRef<WebSocket | null>(null)
useEffect(() => {
// Load initial data
fetch('/api/tasks')
.then(res => res.json())
.then(data => setTasks(data.docs))
// Connect WebSocket
ws.current = new WebSocket('ws://localhost:3000/api/ws')
ws.current.onmessage = (event) => {
const msg = JSON.parse(event.data)
if (msg.event === 'ws:ready') {
// Join tasks room
ws.current?.send(JSON.stringify({
type: 'join',
room: 'tasks'
}))
}
if (msg.event === 'task:changed') {
// Update task in real-time
setTasks(prev => {
const exists = prev.find(t => t.id === msg.data.id)
if (exists) {
return prev.map(t => t.id === msg.data.id ? msg.data : t)
} else {
return [...prev, msg.data]
}
})
}
}
return () => ws.current?.close()
}, [])
return (
<div>
<h1>Real-time Tasks</h1>
{tasks.map(task => (
<div key={task.id}>
{task.title} - {task.completed ? '✅' : '⏳'}
</div>
))}
</div>
)
}📚 API Reference
Broadcasting Functions
broadcastToUser(userId, event, data)
Send to all connections of a specific user.
broadcastToRoom(roomName, event, data, except?)
Send to all sockets in a room, optionally excluding one.
broadcastToAllUsers(event, data)
Send to all connected clients.
emitToSocket(socket, event, data)
Send to a specific socket.
Room Functions
joinRoom(socket, roomName)
Add socket to a room.
leaveRoom(socket, roomName)
Remove socket from a room.
leaveAllRooms(socket)
Remove socket from all rooms.
getRoomSockets(roomName)
Get all sockets in a room.
getSocketRooms(socket)
Get all rooms a socket is in.
Utility Functions
getConnectionStats()
Get connection statistics.
debugConnections()
Log all connections for debugging.
� Support & Donations
This project is free and open source for non-commercial use. If you find it useful, please consider supporting its development:
💰 Donate
- GitHub Sponsors: https://github.com/sponsors/erickpajares
- PayPal: [Add your PayPal link]
- Ko-fi: [Add your Ko-fi link]
- Buy Me a Coffee: [Add your link]
🤝 Other Ways to Support
- ⭐ Star this repository
- 🐛 Report bugs and issues
- 📝 Contribute to documentation
- 💡 Share feature ideas
- 🔀 Submit pull requests
📄 License
Non-Commercial License - Free for non-commercial use only.
This software may NOT be used for commercial purposes without explicit permission.
- ✅ Free for personal projects
- ✅ Free for educational use
- ✅ Free for open-source projects
- ❌ Cannot be sold or commercialized
- ❌ Cannot be used in paid products/services
For commercial licensing, please contact: [email protected]
See LICENSE for full details.
👤 Author
Erick Pajares
Digital Andes Perú
- GitHub: @erickpajares
- Email: [email protected]
🤝 Contributing
Issues and PRs welcome!
Made with ❤️ by Erick Pajares - Digital Andes Perú
