playsocketjs 2.6.1 → 2.6.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
@@ -7,7 +7,7 @@ A reactive, optimistic WebSocket library that simplifies game & app development
7
7
  PlaySocket eliminates the traditional complexity of collaborative experiences:
8
8
 
9
9
  - **Streamlined architecture**: No additional backend code is required, but server-authoritative behavior supported
10
- - **State synchronization**: Built-in storage system keeps the full state synchronized across all clients, always conflict-free and in order
10
+ - **State synchronization**: Built-in storage system keeps the full state synchronized across all clients, always conflict-free and in order
11
11
  - **Resilient & secure connections**: Automatic reconnection handling & strict rate-limiting
12
12
  - **Lightweight**: Uses WebSockets for efficient, predictable, reliable communication and has little dependencies
13
13
 
@@ -19,7 +19,7 @@ npm install playsocketjs
19
19
 
20
20
  ## Usage examples
21
21
 
22
- Note that in production, you should **always try...catch** promises, such as socket.init() – they can reject!
22
+ Note that in production, you should **always try...catch** promises, such as socket.init() – they can reject!
23
23
 
24
24
  Initializing the client:
25
25
  ```javascript
@@ -77,7 +77,7 @@ Sending traditional requests to the server:
77
77
  socket.sendRequest('chosen-request-name', { fact: "You can build server-authoritative logic using this!" })
78
78
  ```
79
79
 
80
- ## API Reference
80
+ ## API reference
81
81
 
82
82
  ### Constructor
83
83
 
@@ -89,36 +89,45 @@ new PlaySocket(id?: string, options: PlaySocketOptions)
89
89
  ```
90
90
 
91
91
  #### Configuration options
92
- - `endpoint`: WebSocket server endpoint (e.g., 'wss://example.com/socket')
93
- - `customData`: You can pass arbitrary data to the "clientRegistered" server event (optional)
94
- - `debug`: Set this property to true to enable extra logging
95
92
 
96
- ### Methods
97
-
98
- - `init()`: Initialize the WebSocket connection – Returns Promise (async) which resolves with the client's ID
99
- - `createRoom(initialStorage?: object, size?: number)`: Create a new room and become host – Returns Promise (async) which resolves with the room ID. The room participant maximum is 100
100
- - `joinRoom(hostId: string)`: Join an existing room – Returns Promise (async)
101
- - `destroy()`: Use this to leave a room and close the connection
102
- - `updateStorage(key: string, type: 'set' | 'array-add' | 'array-add-unique' | 'array-remove-matching' | 'array-update-matching', value: any, updateValue?: any)`: Update a key in the shared storage (max. 100 keys). Array operation types allow for conflict-free simultaneous array updates. For '-matching' operations, value becomes the value to match, and updateValue the replacement.
103
- - `sendRequest(name: string, data?: any)`: Send requests to the server with optional custom data (handle these in the `requestReceived` server event)
104
- - `onEvent(event: string, callback: Function)`: Register an event callback
93
+ | Option | Type | Default | Description |
94
+ |--------|------|---------|-------------|
95
+ | `endpoint` | string | `none - set this!` | WebSocket server endpoint (e.g., 'wss://example.com/socket') |
96
+ | `customData` | object | `{}` | Arbitrary data to pass to the "clientRegistered" server event (optional) |
97
+ | `debug` | boolean | `false` | Set to true to enable extra logging |
105
98
 
106
- #### Event types
99
+ ### Methods
107
100
 
108
- - `status`: Connection status updates (returns status `string`)
109
- - `error`: Error events (returns error `string`)
110
- - `instanceDestroyed`: Destruction event - triggered by manual .destroy() method invocation or by fatal errors and disconnects
111
- - `storageUpdated`: Storage state changes (returns storage `object`)
112
- - `hostMigrated`: Host changes (returns the new host's ID `string`)
113
- - `clientConnected`: New client connected to the room (returns client's ID `string`)
114
- - `clientDisconnected`: Client disconnected from the room (returns client's ID `string`, room ID (if available) `string`)
101
+ | Method | Parameters | Return type | Description |
102
+ |--------|------------|-------------|-------------|
103
+ | `init()` | - | `Promise<string>` | Initialize the WebSocket connection – Returns Promise which resolves with the client's ID |
104
+ | `createRoom()` | `initialStorage?: object, size?: number` | `Promise<string>` | Create a new room and become host – Returns Promise which resolves with the room ID. The room participant maximum is 100 |
105
+ | `joinRoom()` | `roomId: string` | `Promise<void>` | Join an existing room |
106
+ | `destroy()` | - | `void` | Use this to leave a room and close the connection |
107
+ | `updateStorage()` | `key: string, type: 'set' \| 'array-add' \| 'array-add-unique' \| 'array-remove-matching' \| 'array-update-matching', value: any, updateValue?: any` | `void` | Update a key in the shared storage (max. 100 keys). Array operation types allow for conflict-free simultaneous array updates. For '-matching' operations, value becomes the value to match, and updateValue the replacement |
108
+ | `sendRequest()` | `name: string, data?: any` | `void` | Send requests to the server with optional custom data (handle these in the `requestReceived` server event) |
109
+ | `onEvent()` | `event: string, callback: Function` | `void` | Register an event callback |
110
+
111
+ ### Event types
112
+
113
+ | Event | Callback parameter | Description |
114
+ |-------|-------------------|-------------|
115
+ | `status` | `status: string` | Connection status updates |
116
+ | `error` | `error: string` | Error events |
117
+ | `instanceDestroyed` | - | Destruction event - triggered by manual .destroy() method invocation or by fatal errors and disconnects |
118
+ | `storageUpdated` | `storage: object` | Storage state changes |
119
+ | `hostMigrated` | `roomId: string` | Host changes |
120
+ | `clientConnected` | `clientId: string` | New client connected to the room |
121
+ | `clientDisconnected` | `clientId: string, roomId?: string` | Client disconnected from the room |
115
122
 
116
123
  ### Properties (Read-only)
117
124
 
118
- - `id`: Client's unique identifier on the WebSocket server
119
- - `isHost`: If this user is currently assigned the host role
120
- - `connectionCount`: Number of active client connections in room (without yourself)
121
- - `getStorage`: Retrieve storage object
125
+ | Property | Type | Description |
126
+ |----------|------|-------------|
127
+ | `id` | string | Client's unique identifier on the WebSocket server |
128
+ | `isHost` | boolean | If this user is currently assigned the host role |
129
+ | `connectionCount` | number | Number of active client connections in room (without yourself) |
130
+ | `getStorage` | object | Retrieve storage object |
122
131
 
123
132
  &nbsp;
124
133
 
@@ -188,51 +197,59 @@ process.on('SIGINT', shutdown);
188
197
  process.on('SIGTERM', shutdown);
189
198
  ```
190
199
 
191
- ## API Reference
200
+ ## API reference
192
201
 
193
202
  ### Constructor
194
203
 
204
+ Creates a new PlaySocket Server instance with configuration options.
205
+
195
206
  ```javascript
196
207
  new PlaySocket(options: PlaySocketServerOptions)
197
208
  ```
198
209
 
199
- Creates a new PlaySocket Server instance with configuration options.
200
-
201
210
  ### Configuration options
202
211
 
203
- - `port`: Port to listen on (default: 3000, used only if no server provided)
204
- - `path`: WebSocket endpoint path (default: '/')
205
- - `server`: Existing http server (optional)
206
- - `rateLimit`: Adjust the messages/second rate limit (defaults to 20)
207
- - `debug`: Set this property to true to enable extra logging
212
+ | Option | Type | Default | Description |
213
+ |--------|------|---------|-------------|
214
+ | `port` | number | 3000 | Port to listen on (used only if no server provided) |
215
+ | `path` | string | '/' | WebSocket endpoint path |
216
+ | `server` | http.Server | - | Existing http server (optional) |
217
+ | `rateLimit` | number | 20 | Adjust the messages/second rate limit |
218
+ | `debug` | boolean | false | Set to true to enable extra logging |
208
219
 
209
220
  ### Methods
210
221
 
211
- - `stop`: Closes all active client connections, the websocket server and the underlying http server if it's standalone
212
- - `kick(clientId: string, reason?: string)`: Kick a client by their clientID – this will close their connection and set an error message
213
- - `onEvent(event: string, callback: Function)`: Register a server-side event callback
214
- - `getRoomStorage(roomId: string)`: Get a snapshot of the current room storage (returns storage `object`)
215
- - `updateRoomStorage(roomId: string, key: string, type: 'set' | 'array-add' | 'array-add-unique' | 'array-remove-matching' | 'array-update-matching', value: any, updateValue?: any)`: Update a key in the shared room storage from the server.
216
- - `createRoom(initialStorage?: object, size?: number, host?: string)`: Create a room (returns `object` containing room ID and state) – Rooms created with a non-player host like "server" (default) will not be deleted when the last participant leaves
217
- - `destroyRoom(roomId: string)`: Destroy a room & kick all participants
218
-
219
- #### Event types
220
-
221
- - `clientRegistered`: Client registered with the server (returns the client's ID `string`, customData `object`)
222
- - `clientRegistrationRequested`: Client requests to register (returns the client's ID `string`, customData `object`) – return `false` or a rejection reason `string` to block the registration
223
- - `clientDisconnected`: Client disconnected from the server (returns the client's ID `string`)
224
- - `clientJoinedRoom`: Client joined a room – note that clients can only leave by disconnecting (returns the client's ID `string`, room ID `string`)
225
- - `clientJoinRequested`: Client requests to join a room (returns the client's ID `string`, room ID `string`) – return `false` or a rejection reason `string` to block them from joining
226
- - `roomCreated`: Client created a room (returns room ID `string`)
227
- - `roomDestroyed`: Room was destroyed, this happens when all participants leave (returns room ID `string`)
228
- - `roomCreationRequested`: Room creation requested by client (returns `object` containing the client's ID `string` and the initialStorage `object`) – if you return an `object` in the callback, it will take that as the initial storage instead. If you return `false`, the creation will be denied
229
- - `storageUpdated`: Room storage property updated (returns `object` containing the ID of the client who requested the update `string`, room ID `string`, the update `object`, and the storage `object`)
230
- - `storageUpdateRequested`: Room storage property update requested by client (returns `object` containing the client's ID `string`, room ID `string`, the update `object`, and the current storage `object` that hasn't been updated yet) – if you return `false` in the callback, the update will be blocked
231
- - `requestReceived`: Request from client was received by the server (returns `object` containing client's ID `string`, if in room – room ID `string`, request name `string` and optional passed data of type `any`)
222
+ | Method | Parameters | Return type | Description |
223
+ |--------|------------|-------------|-------------|
224
+ | `stop()` | - | `void` | Closes all active client connections, the websocket server and the underlying http server if it's standalone |
225
+ | `kick()` | `clientId: string, reason?: string` | `void` | Kick a client by their clientID – this will close their connection and set an error message |
226
+ | `onEvent()` | `event: string, callback: Function` | `void` | Register a server-side event callback |
227
+ | `getRoomStorage()` | `roomId: string` | `object` | Get a snapshot of the current room storage |
228
+ | `updateRoomStorage()` | `roomId: string, key: string, type: 'set' \| 'array-add' \| 'array-add-unique' \| 'array-remove-matching' \| 'array-update-matching', value: any, updateValue?: any` | `void` | Update a key in the shared room storage from the server |
229
+ | `createRoom()` | `initialStorage?: object, size?: number, host?: string` | `Promise<object>` | Create a room (returns object containing room ID and state) – Rooms created with a non-player host like "server" (default) will not be deleted when the last participant leaves |
230
+ | `destroyRoom()` | `roomId: string` | `void` | Destroy a room & kick all participants |
231
+
232
+ ### Event types
233
+
234
+ | Event | Callback parameters | Description | Return for action |
235
+ |-------|-------------------|-------------|--------------|
236
+ | `clientRegistered` | `clientId: string, customData: object` | Client registered with the server | - |
237
+ | `clientRegistrationRequested` | `clientId: string, customData: object` | Client requests to register | Return `false` or rejection reason `string` to block |
238
+ | `clientDisconnected` | `clientId: string` | Client disconnected from the server | - |
239
+ | `clientJoinedRoom` | `clientId: string, roomId: string` | Client joined a room (clients can only leave by disconnecting) | - |
240
+ | `clientJoinRequested` | `clientId: string, roomId: string` | Client requests to join a room | Return `false` or rejection reason `string` to block |
241
+ | `roomCreated` | `roomId: string` | Client created a room | - |
242
+ | `roomDestroyed` | `roomId: string` | Room was destroyed (happens when all participants leave) | - |
243
+ | `roomCreationRequested` | `{clientId: string, initialStorage: object}` | Room creation requested by client | Return `object` to override initial storage, `false` to deny |
244
+ | `storageUpdated` | `{clientId: string, roomId: string, update: object, storage: object}` | Room storage property updated | - |
245
+ | `storageUpdateRequested` | `{clientId: string, roomId: string, update: object, storage: object}` | Room storage property update requested by client | Return `false` to block the update |
246
+ | `requestReceived` | `{clientId: string, roomId?: string, requestName: string, data?: any}` | Request from client was received by the server | - |
232
247
 
233
248
  ### Properties (Read-only)
234
249
 
235
- - `getRooms`: Retrieve the rooms object
250
+ | Property | Type | Description |
251
+ |----------|------|-------------|
252
+ | `getRooms` | object | Retrieve the rooms object |
236
253
 
237
254
  # License
238
255
 
@@ -2284,25 +2284,16 @@ class PlaySocketServer {
2284
2284
  return;
2285
2285
  }
2286
2286
 
2287
- // Event callback with potential initial storage modifications
2288
- const reviewedStorage = await this.#triggerEvent("roomCreationRequested", { clientId: ws.clientId, initialStorage: structuredClone({ ...data.initialStorage }) });
2289
- if (typeof reviewedStorage === 'object') data.initialStorage = reviewedStorage;
2290
- if (reviewedStorage === false) {
2291
- ws.send(encode({
2292
- type: 'room_creation_failed',
2293
- reason: 'Room creation denied.'
2294
- }), { binary: true });
2295
- return;
2296
- }
2287
+ try {
2288
+ const newRoom = await this.createRoom(data.initialStorage, data.size, ws.clientId);
2297
2289
 
2298
- // Check if client/creator is still connected - abort if not
2299
- if (!this.#clients.has(ws.clientId)) {
2300
- if (this.#debug) console.log(`Room creation cancelled - client ${ws.clientId} disconnected during event callback.`);
2301
- return;
2302
- }
2290
+ // Check if client/creator is still connected - abort if not
2291
+ if (!this.#clients.has(ws.clientId)) {
2292
+ this.destroyRoom(newRoom.id);
2293
+ if (this.#debug) console.log(`Room creation cancelled - client ${ws.clientId} disconnected during event callback.`);
2294
+ return;
2295
+ }
2303
2296
 
2304
- try {
2305
- const newRoom = this.createRoom(data.initialStorage, data.size, ws.clientId);
2306
2297
  this.#rooms[newRoom.id].participants.push(ws.clientId); // Add client to the room
2307
2298
  this.#clientRooms.set(ws.clientId, newRoom.id); // Add client to the client-room map
2308
2299
  ws.send(encode({ type: 'room_created', state: newRoom.state, roomId: newRoom.id }), { binary: true });
@@ -2640,12 +2631,18 @@ class PlaySocketServer {
2640
2631
 
2641
2632
  /**
2642
2633
  * Create a room from the server
2634
+ * @async
2643
2635
  * @param {object} [initialStorage] - Optional initial storage object
2644
2636
  * @param {number} [size] - Max. room size, up to 500
2645
2637
  * @param {string} [host] - Host ID, defaults to "server" (when set to "server", room will not be deleted if all clients leave)
2646
- * @returns {object} Object containing room state and room ID
2638
+ * @returns {Promise<object>} Object containing room state and room ID
2647
2639
  */
2648
- createRoom(initialStorage, size, host = "server") {
2640
+ async createRoom(initialStorage, size, host = "server") {
2641
+ // Event callback with potential initial storage modifications
2642
+ const reviewedStorage = await this.#triggerEvent("roomCreationRequested", { clientId: host, initialStorage: structuredClone({ ...initialStorage }) });
2643
+ if (typeof reviewedStorage === 'object') initialStorage = reviewedStorage;
2644
+ if (reviewedStorage === false) throw new Error("Room creation denied.");
2645
+
2649
2646
  let newRoomId;
2650
2647
 
2651
2648
  for (let i = 0; i < 100; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playsocketjs",
3
- "version": "2.6.1",
3
+ "version": "2.6.2",
4
4
  "description": "WebSocket wrapper for creating simple multiplayer systems with ease.",
5
5
  "type": "module",
6
6
  "module": "dist/playsocket-client.js",