Replies: 7 comments 7 replies
-
Duplicate of #2534 Would love this feature! |
Beta Was this translation helpful? Give feedback.
-
Considering the move to Next.js and the likeliness many people will be deploying Payload in the same app as their frontend on Vercel (or other serverless environments), how would this work? Would a WebSocket service be a standalone feature of Payload Cloud, perhaps? |
Beta Was this translation helpful? Give feedback.
-
Is there any timing on this? Just trying to plan for a project I have coming up in the next couple months that will need this feature. |
Beta Was this translation helpful? Give feedback.
-
@zubricks WebSockets are not a feature as described here, it's a protocol. So please clarify, as its essential from my perspective that such a discussion uses the correct terms especially if a feature is flagged with priority 1. |
Beta Was this translation helpful? Give feedback.
-
Is there a branch that has been start for this feature? Looking to contribute to this feature |
Beta Was this translation helpful? Give feedback.
-
PayloadCMS and FeathersJS are my go-to Node.js frameworks, the last for Real-time Apps. I'd love to see how this will be implemented and the API you'll provide to interact with events and subscriptions. |
Beta Was this translation helpful? Give feedback.
-
I'm having a good time using socket.io with payload. You can use Payloads local API in the socket.io handlers and the socket.io instance in Payload CMS hooks. With socket.io client libraries in your frontend, you can do whatever you want. With adapters, you can connect socket.io to your DB to scale this approach to multiple server instances, leveraging MongoDB change streams. I wonder if that gets more complicated when moving to Payload CMS v3. In my case, my client app needs to refresh its data on changes. So I emit poke events after relevant change or delete events. This was very straightforward, since socket.io is served from the same server as I can access the auth cookie. Here is the server-side setup. // example for hooks, that send poke events into organization rooms
import { extractId } from "./utils";
import { io } from "../../socket-io";
import {
CollectionAfterChangeHook,
CollectionAfterDeleteHook,
} from "payload/types";
export const sendOrganizationPokeAfterChange: CollectionAfterChangeHook =
async ({ doc }) => {
if (!doc.organization) return;
const orgID = extractId(doc.organization);
io.to(orgID).emit("poke");
};
export const sendOrganizationPokeAfterDelete: CollectionAfterDeleteHook =
async ({ doc }) => {
if (!doc.organization) return;
const orgID = extractId(doc.organization);
io.to(orgID).emit("poke");
}; // setting up socket.io
import { Server as HTTPServer } from "node:http";
import payload from "payload";
import { Socket, Server as SocketIOServer } from "socket.io";
import { z } from "zod";
import { extractId } from "./utils";
import { createAdapter } from "@socket.io/mongo-adapter";
import { MongoClient } from "mongodb";
export let io: SocketIOServer;
export async function initSocketIO(server: HTTPServer) {
io = new SocketIOServer(server, {
/* options */
});
io.on("connection", hanleOnConnection);
await initMongoDBConnection(io);
return io;
}
/**
* when the request comes from a logged in user,
* add this socket into every organization room that
* this user is member of
*/
async function hanleOnConnection(socket: Socket) {
const { user } = await checkAuthCookie(socket.request.headers.cookie);
if (!user) {
socket.disconnect(true);
return;
}
const organizationIDs = user?.organizations?.map((v) =>
extractId(v.organization),
);
for (const orgID of organizationIDs ?? []) {
socket.join(orgID);
}
}
// this is where socket.io can leverage mongodb to support messaging accross multiple server instances
async function initMongoDBConnection(io: SocketIOServer) {
const mongoClient = new MongoClient(process.env.DATABASE_URI as string);
await mongoClient.connect();
const mongoCollection = mongoClient
.db()
.collection("socket.io-adapter-events");
await mongoCollection.createIndex(
{ createdAt: 1 },
{ expireAfterSeconds: 3600, background: true },
);
io.adapter(
createAdapter(mongoCollection as any, {
addCreatedAtField: true,
}),
);
} // when starting your server, attach socket.io to the http server
import { createServer } from "node:http";
import "dotenv/config";
import { initSocketIO } from "./socket-io";
import { initPayload } from "./payload";
import { initExpress } from "./express";
const main = async () => {
const app = initExpress();
const httpServer = createServer(app);
await initPayload(app);
initSocketIO(httpServer);
httpServer.listen(3000);
};
main(); |
Beta Was this translation helpful? Give feedback.
-
WebSockets are a powerful feature that we plan to bring to Payload. With WebSockets you’ll be able to subscribe to when documents are created, updated, or deleted over the same connection.
This means you’d be able to build things like data driven dashboards, notification systems, and more.
Beta Was this translation helpful? Give feedback.
All reactions