payload-socket-plugin 1.1.0 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,7 +18,7 @@ Real-time event broadcasting plugin for Payload CMS using Socket.IO with Redis s
18
18
  ## Prerequisites
19
19
 
20
20
  - **Node.js**: >= 20.0.0
21
- - **Payload CMS**: >= 2.0.0
21
+ - **Payload CMS**: ^2.0.0 || ^3.0.0
22
22
  - **Redis** (optional): Required for multi-instance deployments
23
23
 
24
24
  ## Installation
@@ -61,15 +61,17 @@ export default buildConfig({
61
61
  },
62
62
  path: "/socket.io",
63
63
  },
64
- includeCollections: ["projects", "posts"],
64
+ includeCollections: ["posts", "users"],
65
65
  authorize: {
66
- projects: async (user, event) => {
67
- // Only allow project owner to receive events
68
- return user.id === event.doc.user;
69
- },
70
66
  posts: async (user, event) => {
71
67
  // Allow everyone to receive public post events
72
- return event.doc.isPublic || user.id === event.doc.user;
68
+ return (
69
+ event.doc.status === "published" || user.id === event.doc.author
70
+ );
71
+ },
72
+ users: async (user, event) => {
73
+ // Only allow user to receive their own events
74
+ return user.id === event.id;
73
75
  },
74
76
  },
75
77
  }),
@@ -115,16 +117,16 @@ const socket = io("http://localhost:3000", {
115
117
  });
116
118
 
117
119
  // Subscribe to collection events
118
- socket.emit("join-collection", "projects");
120
+ socket.emit("join-collection", "posts");
119
121
 
120
122
  // Listen for events
121
123
  socket.on("payload:event", (event) => {
122
124
  console.log("Event received:", event);
123
125
  // {
124
126
  // type: 'update',
125
- // collection: 'projects',
127
+ // collection: 'posts',
126
128
  // id: '123',
127
- // doc: { ... },
129
+ // doc: { title: 'My Post', status: 'published', ... },
128
130
  // user: { id: '456', email: 'user@example.com' },
129
131
  // timestamp: '2024-01-01T00:00:00.000Z'
130
132
  // }
@@ -153,28 +155,25 @@ Authorization handlers determine which users can receive events for specific doc
153
155
  ```typescript
154
156
  import type { CollectionAuthorizationHandler } from "payload-socket-plugin";
155
157
 
156
- const authorizeProject: CollectionAuthorizationHandler = async (
157
- user,
158
- event
159
- ) => {
158
+ const authorizePost: CollectionAuthorizationHandler = async (user, event) => {
160
159
  // Admin can see all events
161
160
  if (user.role === "admin") {
162
161
  return true;
163
162
  }
164
163
 
165
- // Check if user owns the project
166
- const project = await payload.findByID({
167
- collection: "projects",
164
+ // Check if post is published or user is the author
165
+ const post = await payload.findByID({
166
+ collection: "posts",
168
167
  id: event.id as string,
169
168
  });
170
169
 
171
- return user.id === project.user;
170
+ return post.status === "published" || user.id === post.author;
172
171
  };
173
172
 
174
173
  // Use in plugin config
175
174
  socketPlugin({
176
175
  authorize: {
177
- projects: authorizeProject,
176
+ posts: authorizePost,
178
177
  },
179
178
  });
180
179
  ```
@@ -185,13 +184,13 @@ socketPlugin({
185
184
 
186
185
  ```typescript
187
186
  // Subscribe to a single collection
188
- socket.emit("join-collection", "projects");
187
+ socket.emit("join-collection", "posts");
189
188
 
190
189
  // Subscribe to multiple collections
191
- socket.emit("subscribe", ["projects", "posts"]);
190
+ socket.emit("subscribe", ["posts", "users", "media"]);
192
191
 
193
192
  // Unsubscribe
194
- socket.emit("unsubscribe", ["projects"]);
193
+ socket.emit("unsubscribe", ["posts"]);
195
194
  ```
196
195
 
197
196
  ### Listening for Events
@@ -199,8 +198,8 @@ socket.emit("unsubscribe", ["projects"]);
199
198
  ```typescript
200
199
  // Listen to specific collection events
201
200
  socket.on("payload:event", (event) => {
202
- if (event.collection === "projects" && event.type === "update") {
203
- // Handle project update
201
+ if (event.collection === "posts" && event.type === "update") {
202
+ // Handle post update
204
203
  }
205
204
  });
206
205
 
@@ -346,6 +345,16 @@ socketPlugin({
346
345
  4. Authorization handlers determine which users receive the event
347
346
  5. Redis adapter ensures events sync across multiple server instances
348
347
 
348
+ ## Browser Compatibility
349
+
350
+ This plugin includes automatic browser-safe mocking for the Payload admin panel. When bundled for the browser (e.g., in the Payload admin UI), the plugin automatically uses a mock implementation that:
351
+
352
+ - Returns the config unchanged (no Socket.IO server initialization)
353
+ - Provides no-op functions for `initSocketIO()` and `SocketIOManager` methods
354
+ - Prevents server-side dependencies (Socket.IO, Redis) from being bundled in the browser
355
+
356
+ This is handled automatically via the `"browser"` field in `package.json`, so you don't need to configure anything special. The Socket.IO server only runs on the server side.
357
+
349
358
  ## Environment Variables
350
359
 
351
360
  ```bash
@@ -428,7 +437,6 @@ import type {
428
437
 
429
438
  ## Known Limitations
430
439
 
431
- - Only supports Payload CMS v2.x (v3.x support coming soon)
432
440
  - Authorization handlers are called for each connected user on every event
433
441
  - No built-in event replay or history mechanism
434
442
  - Redis is required for multi-instance deployments
@@ -0,0 +1,19 @@
1
+ import type { Config } from "payload";
2
+ /**
3
+ * Browser-safe mock for the Socket.IO plugin
4
+ * This file is used when bundling for the browser (e.g., Payload admin panel)
5
+ * The actual Socket.IO server only runs on the server side
6
+ */
7
+ export declare const socketPlugin: () => (config: Config) => Config;
8
+ /**
9
+ * Browser-safe mock for initSocketIO
10
+ * Does nothing in browser environment
11
+ */
12
+ export declare const initSocketIO: (httpServer?: any) => Promise<void>;
13
+ /**
14
+ * Browser-safe mock for SocketIOManager
15
+ * Returns a minimal mock class in browser environment
16
+ */
17
+ export declare class SocketIOManager {
18
+ constructor();
19
+ }
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SocketIOManager = exports.initSocketIO = exports.socketPlugin = void 0;
4
+ /**
5
+ * Browser-safe mock for the Socket.IO plugin
6
+ * This file is used when bundling for the browser (e.g., Payload admin panel)
7
+ * The actual Socket.IO server only runs on the server side
8
+ */
9
+ const socketPlugin = () => (config) => {
10
+ // Return config unchanged - Socket.IO server is server-side only
11
+ return config;
12
+ };
13
+ exports.socketPlugin = socketPlugin;
14
+ /**
15
+ * Browser-safe mock for initSocketIO
16
+ * Does nothing in browser environment
17
+ */
18
+ const initSocketIO = async (httpServer) => {
19
+ // No-op in browser
20
+ console.warn("initSocketIO called in browser environment - this is a no-op");
21
+ };
22
+ exports.initSocketIO = initSocketIO;
23
+ /**
24
+ * Browser-safe mock for SocketIOManager
25
+ * Returns a minimal mock class in browser environment
26
+ */
27
+ class SocketIOManager {
28
+ constructor() {
29
+ // No-op in browser
30
+ }
31
+ }
32
+ exports.SocketIOManager = SocketIOManager;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { Plugin } from "payload/config";
1
+ import type { Config } from "payload";
2
2
  import { RealtimeEventsPluginOptions } from "./types";
3
+ type Plugin = (config: Config) => Config;
3
4
  /**
4
5
  * Payload CMS Plugin for Real-time Events
5
6
  *
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "payload-socket-plugin",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Real-time Socket.IO plugin for Payload CMS with Redis support",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
- "browser": "dist/mock.js",
7
+ "browser": "dist/browser.js",
8
8
  "files": [
9
9
  "dist",
10
10
  "README.md"
@@ -30,9 +30,6 @@
30
30
  "engines": {
31
31
  "node": ">=20.0.0"
32
32
  },
33
- "peerDependencies": {
34
- "payload": "^2.0.0"
35
- },
36
33
  "dependencies": {
37
34
  "@socket.io/redis-adapter": "^8.0.0",
38
35
  "ioredis": "^5.3.0",
@@ -42,7 +39,6 @@
42
39
  "devDependencies": {
43
40
  "@types/jsonwebtoken": "^9.0.0",
44
41
  "@types/node": "^20.0.0",
45
- "payload": "^2.0.0",
46
42
  "typescript": "^5.0.0"
47
43
  },
48
44
  "repository": {
package/dist/mock.d.ts DELETED
@@ -1,13 +0,0 @@
1
- /**
2
- * Mock module for socket plugin
3
- * Used by webpack to prevent bundling server-side Socket.IO code in the admin panel
4
- *
5
- * This is aliased in payload.config.ts webpack configuration:
6
- * [socketPluginPath]: socketPluginMockPath
7
- */
8
- import { Config } from "payload/config";
9
- /**
10
- * Mock plugin that does nothing
11
- * The real plugin is only used on the server side
12
- */
13
- export declare const socketPlugin: () => (config: Config) => Config;
package/dist/mock.js DELETED
@@ -1,19 +0,0 @@
1
- "use strict";
2
- /**
3
- * Mock module for socket plugin
4
- * Used by webpack to prevent bundling server-side Socket.IO code in the admin panel
5
- *
6
- * This is aliased in payload.config.ts webpack configuration:
7
- * [socketPluginPath]: socketPluginMockPath
8
- */
9
- Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.socketPlugin = void 0;
11
- /**
12
- * Mock plugin that does nothing
13
- * The real plugin is only used on the server side
14
- */
15
- const socketPlugin = () => (config) => {
16
- // Return config unchanged - no Socket.IO in admin panel
17
- return config;
18
- };
19
- exports.socketPlugin = socketPlugin;