playsocketjs 2.1.1 → 2.2.0

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
@@ -72,6 +72,11 @@ socket.updateStorage('players', 'array-add-unique', { username: 'Player4', level
72
72
  socket.updateStorage('latestPlayer', 'set', 'Player4'); // Regular synced storage update
73
73
  ```
74
74
 
75
+ Sending traditional requests to the server:
76
+ ```javascript
77
+ socket.sendRequest('chosen-request-name', { fact: "You can build server-authoritative logic using this!" })
78
+ ```
79
+
75
80
  ## API Reference
76
81
 
77
82
  ### Constructor
@@ -95,6 +100,7 @@ new PlaySocket(id?: string, options: PlaySocketOptions)
95
100
  - `joinRoom(hostId: string)`: Join an existing room – Returns Promise (async)
96
101
  - `destroy()`: Use this to leave a room and close the connection
97
102
  - `updateStorage(key: string, type: 'set' | 'array-add' | 'array-add-unique' | 'array-remove-matching' | 'array-update-matching', value: any, updateValue?: any)`: Update the shared storage. Safely update arrays in storage by adding, removing, or updating items. UpdateValue is only required for the 'array-update-matching' operation type
103
+ - `sendRequest(name: string, data?: any)`: Send requests to the server with optional custom data (handle these in the `requestReceived` server event)
98
104
  - `onEvent(event: string, callback: Function)`: Register an event callback
99
105
 
100
106
  #### Event types
@@ -111,7 +117,7 @@ new PlaySocket(id?: string, options: PlaySocketOptions)
111
117
 
112
118
  - `id`: Client's unique identifier on the WebSocket server
113
119
  - `isHost`: If this user is currently assigned the host role
114
- - `connectionCount`: Number of active client connections in room (without you)
120
+ - `connectionCount`: Number of active client connections in room (without yourself)
115
121
  - `getStorage`: Retrieve storage object
116
122
 
117
123
   
@@ -210,12 +216,14 @@ Creates a new PlaySocket Server instance with configuration options.
210
216
  #### Event types
211
217
 
212
218
  - `clientRegistered`: Client registered with the server (returns the client's ID `string`, customData `object`)
219
+ - `clientRegistrationRequested`: Client requests to register (returns the client's ID `string`, customData `object`) – return `false` or a rejection reason `string` to block the registration
213
220
  - `clientDisconnected`: Client disconnected from the server (returns the client's ID `string`)
214
221
  - `clientJoinedRoom`: Client joined a room – note that clients can only leave by disconnecting (returns the client's ID `string`, room ID `string`)
215
222
  - `roomCreated`: Client created a room (returns room ID `string`)
216
223
  - `roomDestroyed`: Room was destroyed, this happens when all participants leave (returns room ID `string`)
217
224
  - `roomCreationRequested`: Room creation requested by client (returns `object` containing the client's ID `string`, room ID `string` and the initialStorage `object`) – if you return an `object` in the callback, it will take that as the initial storage instead
218
225
  - `storageUpdateRequested`: Room storage property update requested by client (returns `object` containing the client's ID `string`, room ID `string` and the update `object`) – if you return `false` in the callback, the update will be blocked
226
+ - `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`)
219
227
 
220
228
  ### Properties (Read-only)
221
229
 
@@ -2227,6 +2227,22 @@ class PlaySocket {
2227
2227
  if (!message.type) return;
2228
2228
 
2229
2229
  switch (message.type) {
2230
+ case 'registration_failed':
2231
+ if (this.#pendingRegistration) {
2232
+ this.#pendingRegistration.reject(new Error("Failed to register: " + message.reason));
2233
+ this.#triggerEvent("error", "Failed to register: " + message.reason);
2234
+ }
2235
+ break;
2236
+
2237
+ case 'registered':
2238
+ if (this.#pendingRegistration) {
2239
+ this.#sessionToken = message.sessionToken;
2240
+ this.#initialized = true;
2241
+ this.#pendingRegistration.resolve(message.id);
2242
+ this.#triggerEvent("status", "Connected to server.");
2243
+ }
2244
+ break;
2245
+
2230
2246
  case 'join_accepted':
2231
2247
  // Connected to room
2232
2248
  if (this.#pendingJoin) {
@@ -2293,22 +2309,6 @@ class PlaySocket {
2293
2309
  }
2294
2310
  break;
2295
2311
 
2296
- case 'id_taken':
2297
- if (this.#pendingRegistration) {
2298
- this.#pendingRegistration.reject(new Error("This id is already in use"));
2299
- this.#triggerEvent("error", "This id is taken.");
2300
- }
2301
- break;
2302
-
2303
- case 'registered':
2304
- if (this.#pendingRegistration) {
2305
- this.#sessionToken = message.sessionToken;
2306
- this.#initialized = true;
2307
- this.#pendingRegistration.resolve(message.id);
2308
- this.#triggerEvent("status", "Connected to server.");
2309
- }
2310
- break;
2311
-
2312
2312
  case 'property_updated':
2313
2313
  this.#roomVersion++; // Increment room version
2314
2314
  if (this.#debug) console.log(LOG_PREFIX + "Property update received:", message.update);
@@ -2299,7 +2299,7 @@ function requireServer () {
2299
2299
  case 'register':
2300
2300
  // Register client ID if provided & check for a duplicate
2301
2301
  if (data.id && this.#clients.get(data.id)) {
2302
- ws.send(encode({ type: 'id_taken' }), { binary: true });
2302
+ ws.send(encode({ type: 'registration_failed', reason: 'ID is taken.' }), { binary: true });
2303
2303
  return;
2304
2304
  }
2305
2305
 
@@ -2315,11 +2315,20 @@ function requireServer () {
2315
2315
  }
2316
2316
  }
2317
2317
  if (!data.id) {
2318
- ws.send(encode({ type: 'id_taken' }), { binary: true });
2318
+ ws.send(encode({ type: 'registration_failed', reason: 'No available ID found.' }), { binary: true });
2319
2319
  throw new Error('Failed to generate unique ID!');
2320
2320
  }
2321
2321
  }
2322
2322
 
2323
+ // Event callback
2324
+ const registrationAllowed = await this.#triggerEvent("clientRegistrationRequested", data.id, data.customData);
2325
+ if (registrationAllowed === false || typeof registrationAllowed === 'string') {
2326
+ ws.send(encode({
2327
+ type: 'registration_failed',
2328
+ reason: typeof registrationAllowed === 'string' ? registrationAllowed : 'Denied.'
2329
+ }), { binary: true });
2330
+ return;
2331
+ }
2323
2332
 
2324
2333
  ws.clientId = data.id; // Adds the provided id to the ws object as clientId
2325
2334
  this.#clients.set(data.id, ws);
@@ -2464,8 +2473,8 @@ function requireServer () {
2464
2473
 
2465
2474
  if (updateRoom && data.update) {
2466
2475
  // Check if update is allowed via event callback (provide clone to ensure update integrity)
2467
- const allowed = await this.#triggerEvent("storageUpdateRequested", { roomId: updateRoomId, clientId: ws.clientId, update: structuredClone(data.update) });
2468
- if (allowed === false) {
2476
+ const updateAllowed = await this.#triggerEvent("storageUpdateRequested", { roomId: updateRoomId, clientId: ws.clientId, update: structuredClone(data.update) });
2477
+ if (updateAllowed === false) {
2469
2478
  ws.send(encode({
2470
2479
  type: 'property_update_rejected',
2471
2480
  state: updateRoom.crdtManager.getState
@@ -2638,7 +2647,7 @@ function requireServer () {
2638
2647
  * @param {Function} callback - Callback function
2639
2648
  */
2640
2649
  onEvent(event, callback) {
2641
- const validEvents = ["clientRegistered", "clientDisconnected", "clientJoinedRoom", "roomCreationRequested", "requestReceived", "roomCreated", "storageUpdateRequested", "roomDestroyed"];
2650
+ const validEvents = ["clientRegistered", "clientRegistrationRequested", "clientDisconnected", "clientJoinedRoom", "roomCreationRequested", "requestReceived", "roomCreated", "storageUpdateRequested", "roomDestroyed"];
2642
2651
  if (!validEvents.includes(event)) return console.warn(`Invalid PlaySocket event type "${event}"`);
2643
2652
  if (!this.#callbacks.has(event)) this.#callbacks.set(event, []);
2644
2653
  this.#callbacks.get(event).push(callback);
@@ -2669,8 +2678,7 @@ function requireServer () {
2669
2678
  for (const callback of callbacks) {
2670
2679
  try {
2671
2680
  const result = await callback(...args);
2672
- if (result === false) return false; // False = block (in supported events)
2673
- if (typeof result === 'object') return result; // If response object is provided -> pass on
2681
+ if (result != null) return result; // Return any non-null/undefined result
2674
2682
  } catch (error) {
2675
2683
  console.error(`PlaySocket ${event} callback error:`, error);
2676
2684
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playsocketjs",
3
- "version": "2.1.1",
3
+ "version": "2.2.0",
4
4
  "description": "WebSocket wrapper for creating simple multiplayer systems with ease.",
5
5
  "module": "dist/playsocket-client.js",
6
6
  "exports": {