playsocketjs 5.0.0 → 5.1.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
@@ -2,6 +2,8 @@
2
2
 
3
3
  An optimistic-first WebSocket synchronization library. Built for creating multiplayer games & collaborative experiences with reactive web frameworks.
4
4
 
5
+ For an introduction to PlaySocket, visit the [PlaySocket website](https://therealpaulplay.github.io/PlaySocketJS/).
6
+
5
7
  ## Why use PlaySocket?
6
8
 
7
9
  PlaySocket makes developing shared experiences a breeze:
@@ -140,9 +142,9 @@ new PlaySocket(id?: string, options: PlaySocketOptions)
140
142
  | `moved` | `roomId: string` | Moved to different room. |
141
143
  | `instanceDestroyed` | `reason: string` | Instance destroyed through `destroy()` or error. |
142
144
  | `storageUpdated` | `storage: object` | Storage state changed. Does not trigger on no-op updates. |
143
- | `hostMigrated` | `roomId: string` | Host was changed. |
145
+ | `hostMigrated` | `hostId: string` | Host was changed. |
144
146
  | `clientJoined` | `clientId: string` | New client joined the room. |
145
- | `clientLeft` | `clientId: string, roomId?: string` | A client left the room. |
147
+ | `clientLeft` | `clientId: string` | A client left the room. |
146
148
 
147
149
  #### Properties
148
150
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playsocketjs",
3
- "version": "5.0.0",
3
+ "version": "5.1.0",
4
4
  "description": "WebSocket wrapper for creating simple multiplayer systems with ease.",
5
5
  "type": "module",
6
6
  "module": "./src/client/client.js",
@@ -20,6 +20,18 @@ const TIMEOUT_MS = 3000; // 3 second timeout for WS messages
20
20
 
21
21
  /** @typedef {{ resolve: (value?: any) => void, reject: (reason?: any) => void }} PendingPromise */
22
22
 
23
+ /**
24
+ * Event callback types
25
+ * @typedef {object} ClientEventMap
26
+ * @property {(message: string) => void} status
27
+ * @property {(roomId: string) => void} moved
28
+ * @property {(reason: string | undefined) => void} instanceDestroyed
29
+ * @property {(storage: Record<string, any>) => void} storageUpdated
30
+ * @property {(hostId: string) => void} hostMigrated
31
+ * @property {(clientId: string) => void} clientJoined
32
+ * @property {(clientId: string) => void} clientLeft
33
+ */
34
+
23
35
  /**
24
36
  * PlaySocket Client
25
37
  */
@@ -75,11 +87,11 @@ export default class PlaySocket {
75
87
 
76
88
  /**
77
89
  * Create a new PlaySocket instance
78
- * @param {string} [id] - Unique identifier for this client (assigned by the server if omitted)
90
+ * @param {string | null} [id] - Unique identifier for this client (assigned by the server if omitted or null)
79
91
  * @param {PlaySocketOptions} options - Connection options
80
92
  */
81
93
  constructor(id, options = /** @type {PlaySocketOptions} */ ({})) {
82
- this.#id = id;
94
+ this.#id = id ?? undefined;
83
95
  if (options.endpoint) this.#endpoint = options.endpoint;
84
96
  if (options.customData) this.#customData = { ...options.customData };
85
97
  if (options.debug) this.#debug = true; // Enabling extra logging
@@ -89,7 +101,7 @@ export default class PlaySocket {
89
101
  /**
90
102
  * Helper to create timeout promises for create room, join room etc.
91
103
  * @param {string} name - Name of the timeout
92
- * @returns {Promise<never>} - Promise that rejects after the timeout
104
+ * @returns {Promise<never>} Promise that rejects after the timeout
93
105
  */
94
106
  #createTimeout(name) {
95
107
  return new Promise((_, reject) =>
@@ -99,9 +111,10 @@ export default class PlaySocket {
99
111
 
100
112
  /**
101
113
  * Register an event callback
102
- * @param {string} event - Event name
103
- * @param {Function} callback - Callback function
104
- * @returns {Function} - Unsubscribe
114
+ * @template {keyof ClientEventMap} E
115
+ * @param {E} event - Event name
116
+ * @param {ClientEventMap[E]} callback - Callback function
117
+ * @returns {Function} Unsubscribe
105
118
  */
106
119
  onEvent(event, callback) {
107
120
  const validEvents = ["status", "moved", "instanceDestroyed", "storageUpdated", "hostMigrated", "clientJoined", "clientLeft"];
@@ -396,11 +409,11 @@ export default class PlaySocket {
396
409
 
397
410
  /**
398
411
  * Create a new room and become host
399
- * @param {object} [initialStorage] - Initial state
412
+ * @param {object | null} [initialStorage] - Initial state
400
413
  * @param {number} [size] - Max number of participants
401
414
  * @returns {Promise<string>} Resolves with room ID
402
415
  */
403
- async createRoom(initialStorage = {}, size) {
416
+ async createRoom(initialStorage, size) {
404
417
  if (!this.#initialized) throw new Error("Not initialized");
405
418
 
406
419
  return /** @type {Promise<string>} */ (Promise.race([
@@ -422,7 +435,7 @@ export default class PlaySocket {
422
435
  /**
423
436
  * Join an existing room
424
437
  * @param {string} roomId - ID of the room
425
- * @returns {Promise<void>} - Resolves when connected
438
+ * @returns {Promise<void>} Resolves when connected
426
439
  */
427
440
  async joinRoom(roomId) {
428
441
  if (!this.#initialized) throw new Error("Not initialized");
@@ -469,7 +482,7 @@ export default class PlaySocket {
469
482
  * Send a custom request to the server
470
483
  * @param {string} name - Name of the request
471
484
  * @param {*} [data] - Custom data
472
- * @returns {Promise<void>} - Request promise
485
+ * @returns {Promise<void>} Request promise
473
486
  */
474
487
  async sendRequest(name, data) {
475
488
  if (!this.#initialized) throw new Error("Not initialized");
@@ -31,6 +31,25 @@ export const RECONNECT_GRACE_PERIOD = 5000; // Exported for use in tests
31
31
  * @property {CRDTManager} crdtManager - CRDT manager holding the room storage
32
32
  */
33
33
 
34
+ /** @typedef {boolean | string | void} RejectViaStringOrBool */
35
+
36
+ /**
37
+ * Event callback types
38
+ * @typedef {object} ServerEventMap
39
+ * @property {(clientId: string, customData: any) => RejectViaStringOrBool | Promise<RejectViaStringOrBool>} clientRegistrationRequested
40
+ * @property {(clientId: string, customData: any) => void} clientRegistered
41
+ * @property {(clientId: string) => void} clientDisconnected
42
+ * @property {(clientId: string, roomId: string) => void} clientJoinedRoom
43
+ * @property {(clientId: string, roomId: string) => void} clientLeftRoom
44
+ * @property {(clientId: string, roomId: string) => RejectViaStringOrBool | Promise<RejectViaStringOrBool>} clientJoinRequested
45
+ * @property {(roomId: string) => void} roomCreated
46
+ * @property {(roomId: string) => void} roomDestroyed
47
+ * @property {(payload: { clientId: string, initialStorage: Record<string, any> }) => Record<string, any> | RejectViaStringOrBool | Promise<Record<string, any> | RejectViaStringOrBool>} roomCreationRequested
48
+ * @property {(payload: { roomId: string | null, clientId: string, name: string, data: unknown }) => RejectViaStringOrBool | Promise<RejectViaStringOrBool>} requestReceived
49
+ * @property {(payload: { roomId: string, clientId: string, update: PropertyUpdate, storage: Record<string, any> | undefined }) => RejectViaStringOrBool} storageUpdateRequested
50
+ * @property {(payload: { roomId: string, clientId: string | null, update: PropertyUpdate, storage: Record<string, any> | undefined }) => void} storageUpdated
51
+ */
52
+
34
53
  /**
35
54
  * PlaySocket Server
36
55
  */
@@ -358,7 +377,7 @@ export default class PlaySocketServer {
358
377
 
359
378
  /**
360
379
  * Generate a readable, 6 digit ID
361
- * @returns {string} - Id
380
+ * @returns {string} Id
362
381
  */
363
382
  #generateId() {
364
383
  const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789";
@@ -392,7 +411,7 @@ export default class PlaySocketServer {
392
411
 
393
412
  /**
394
413
  * Generate a random token to prevent malicious reconnect attempts
395
- * @returns {string} - Token
414
+ * @returns {string} Token
396
415
  */
397
416
  #generateSessionToken() {
398
417
  let token = "";
@@ -404,7 +423,7 @@ export default class PlaySocketServer {
404
423
  * Check rate limit using token bucket algorithm
405
424
  * @param {string} connUuid - Connection UUID (which is different from the client ID)
406
425
  * @param {string} actionType - A string describing the action
407
- * @returns {boolean} - Whether or not the action can be allowed, true means allowed, false means limited
426
+ * @returns {boolean} Whether or not the action can be allowed, true means allowed, false means limited
408
427
  */
409
428
  #checkRateLimit(connUuid, actionType) {
410
429
  const now = Date.now();
@@ -469,9 +488,10 @@ export default class PlaySocketServer {
469
488
 
470
489
  /**
471
490
  * Register an event callback
472
- * @param {string} event - Event name
473
- * @param {Function} callback - Callback function
474
- * @returns {Function} - Unsubscribe
491
+ * @template {keyof ServerEventMap} E
492
+ * @param {E} event - Event name
493
+ * @param {ServerEventMap[E]} callback - Callback function
494
+ * @returns {Function} Unsubscribe
475
495
  */
476
496
  onEvent(event, callback) {
477
497
  const validEvents = ["clientRegistered", "clientRegistrationRequested", "clientDisconnected", "clientJoinedRoom", "clientLeftRoom", "clientJoinRequested", "roomCreated", "roomCreationRequested", "requestReceived", "storageUpdated", "storageUpdateRequested", "roomDestroyed"];
@@ -494,7 +514,7 @@ export default class PlaySocketServer {
494
514
  * Trigger an event to registered callbacks
495
515
  * @param {string} event - Event name
496
516
  * @param {...*} args - Arguments
497
- * @returns {Promise<any>} - The first non-null callback return value if present (all callbacks run, a throwing callback counts as returning false), otherwise true
517
+ * @returns {Promise<any>} The first non-null callback return value if present (all callbacks run, a throwing callback counts as returning false), otherwise true
498
518
  */
499
519
  async #triggerEvent(event, ...args) {
500
520
  const syncOnlyEvents = ["storageUpdateRequested"]; // Async storage validation could mess up GC and would lead to potentially poor UX (slow sync)
@@ -558,7 +578,7 @@ export default class PlaySocketServer {
558
578
  /**
559
579
  * Get snapshot of a room's storage
560
580
  * @param {string} roomId - ID of the room to get the storage from
561
- * @returns {Record<string, any> | undefined} - Storage object or undefined if the room doesn't exist
581
+ * @returns {Record<string, any> | undefined} Storage object or undefined if the room doesn't exist
562
582
  */
563
583
  getRoomStorage(roomId) {
564
584
  const room = this.#rooms[roomId];
@@ -568,7 +588,7 @@ export default class PlaySocketServer {
568
588
  /**
569
589
  * Get the operation details from a storage update (e.g. in the "storageUpdateRequested" event)
570
590
  * @param {PropertyUpdate} update - Property update
571
- * @returns {{key: string | undefined, type: PropertyUpdateType | undefined, value: *, secondValue: *}} - Operation details
591
+ * @returns {{key: string | undefined, type: PropertyUpdateType | undefined, value: *, secondValue: *}} Operation details
572
592
  */
573
593
  getUpdateDetails(update) {
574
594
  return getUpdateDetails(update);
@@ -606,7 +626,7 @@ export default class PlaySocketServer {
606
626
 
607
627
  /**
608
628
  * Create a server-owned room
609
- * @param {object} [initialStorage] - Optional initial storage object
629
+ * @param {object | null} [initialStorage] - Optional initial storage object
610
630
  * @param {number} [size] - Max. room size, up to 500
611
631
  * @returns {{ state: CRDTState, id: string }} Object containing room state and room ID
612
632
  */
@@ -617,7 +637,7 @@ export default class PlaySocketServer {
617
637
  /**
618
638
  * Create a room
619
639
  * @param {string} host - Host ID (when set to "server", room will not be deleted if all clients leave)
620
- * @param {object} [initialStorage] - Optional initial storage object
640
+ * @param {object | null} [initialStorage] - Optional initial storage object
621
641
  * @param {number} [size] - Max. room size, up to 500
622
642
  * @returns {{ state: CRDTState, id: string }} Object containing room state and room ID
623
643
  */
@@ -9,7 +9,7 @@ export const HEARTBEAT_INTERVAL = 5000;
9
9
  /**
10
10
  * Library version, must match package.json
11
11
  */
12
- export const VERSION = "5.0.0";
12
+ export const VERSION = "5.1.0";
13
13
 
14
14
  /**
15
15
  * Logging prefixes
@@ -179,7 +179,7 @@ export default class CRDTManager {
179
179
  * @param {PropertyUpdateType} type - Operation type
180
180
  * @param {*} value - Value
181
181
  * @param {*} [secondValue] - Second value (needed for some operations)
182
- * @returns {PropertyUpdate | undefined} - Returns the property update
182
+ * @returns {PropertyUpdate | undefined} Returns the property update
183
183
  */
184
184
  updateProperty(key, type, value, secondValue) {
185
185
  try {
@@ -276,7 +276,7 @@ export default class CRDTManager {
276
276
  * Create an operation object
277
277
  * @param {OperationData} data - Operation data, consists of type, value and secondValue
278
278
  * @param {VectorClockEntries} vectorClock - Vector clock of the replica/client
279
- * @returns {Operation} - Operation object
279
+ * @returns {Operation} Operation object
280
280
  */
281
281
  #createOperation(data, vectorClock) {
282
282
  const newOperation = {
@@ -323,7 +323,7 @@ export default class CRDTManager {
323
323
  /**
324
324
  * Sort operations by vector clock (causal order)
325
325
  * @param {Operation[]} operations - Full operations that include vector clocks, data and a source
326
- * @returns {Operation[]} - Sorted operations
326
+ * @returns {Operation[]} Sorted operations
327
327
  */
328
328
  #sortByVectorClock(operations) {
329
329
  return [...operations].sort((a, b) => {
@@ -362,7 +362,7 @@ export default class CRDTManager {
362
362
  * @param {PropertyUpdateType} type - Operation type
363
363
  * @param {*} value - Value
364
364
  * @param {*} [secondValue] - Second value (needed for some operations)
365
- * @returns {*} - Value after the operation
365
+ * @returns {*} Value after the operation
366
366
  */
367
367
  #handleOperation(curValue, type, value, secondValue) {
368
368
  try {
@@ -433,7 +433,7 @@ export default class CRDTManager {
433
433
  /**
434
434
  * Remove HTML to prevent XSS and enforce size limits
435
435
  * @param {*} value - Value to sanitize
436
- * @returns {*} - Sanitized value
436
+ * @returns {*} Sanitized value
437
437
  */
438
438
  #sanitizeValue(value) {
439
439
  if (value === undefined) return null; // Normalize undefined to null to avoid divergence in transport
@@ -450,7 +450,7 @@ export default class CRDTManager {
450
450
 
451
451
  /**
452
452
  * Get property store
453
- * @returns {Record<string, any>} - Object with key value pairs
453
+ * @returns {Record<string, any>} Object with key value pairs
454
454
  */
455
455
  get propertyStore() {
456
456
  try {
@@ -463,7 +463,7 @@ export default class CRDTManager {
463
463
 
464
464
  /**
465
465
  * Check for changes in the local property store
466
- * @returns {boolean} - Check if any values changed going from the last to the current property update
466
+ * @returns {boolean} Check if any values changed going from the last to the current property update
467
467
  */
468
468
  get didPropertiesChange() {
469
469
  try {
@@ -479,7 +479,7 @@ export default class CRDTManager {
479
479
 
480
480
  /**
481
481
  * Export state (can be imported using importState, converts the maps to arrays for serialization)
482
- * @returns {CRDTState} - State
482
+ * @returns {CRDTState} State
483
483
  */
484
484
  get state() {
485
485
  return {
@@ -492,7 +492,7 @@ export default class CRDTManager {
492
492
  /**
493
493
  * Get the operation details from a property update
494
494
  * @param {PropertyUpdate} update - Property update
495
- * @returns {{key: string | undefined, type: PropertyUpdateType | undefined, value: *, secondValue: *}} - Operation details
495
+ * @returns {{key: string | undefined, type: PropertyUpdateType | undefined, value: *, secondValue: *}} Operation details
496
496
  */
497
497
  export function getUpdateDetails(update) {
498
498
  const data = update?.operation?.data;
@@ -23,6 +23,15 @@ export type PendingPromise = {
23
23
  resolve: (value?: any) => void;
24
24
  reject: (reason?: any) => void;
25
25
  };
26
+ export type ClientEventMap = {
27
+ status: (message: string) => void;
28
+ moved: (roomId: string) => void;
29
+ instanceDestroyed: (reason: string | undefined) => void;
30
+ storageUpdated: (storage: Record<string, any>) => void;
31
+ hostMigrated: (hostId: string) => void;
32
+ clientJoined: (clientId: string) => void;
33
+ clientLeft: (clientId: string) => void;
34
+ };
26
35
  /** @typedef {import("../universal/crdtManager.js").PropertyUpdateType} PropertyUpdateType */
27
36
  /**
28
37
  * @typedef {object} PlaySocketOptions
@@ -35,6 +44,17 @@ export type PendingPromise = {
35
44
  * @property {string} type - Message type
36
45
  */
37
46
  /** @typedef {{ resolve: (value?: any) => void, reject: (reason?: any) => void }} PendingPromise */
47
+ /**
48
+ * Event callback types
49
+ * @typedef {object} ClientEventMap
50
+ * @property {(message: string) => void} status
51
+ * @property {(roomId: string) => void} moved
52
+ * @property {(reason: string | undefined) => void} instanceDestroyed
53
+ * @property {(storage: Record<string, any>) => void} storageUpdated
54
+ * @property {(hostId: string) => void} hostMigrated
55
+ * @property {(clientId: string) => void} clientJoined
56
+ * @property {(clientId: string) => void} clientLeft
57
+ */
38
58
  /**
39
59
  * PlaySocket Client
40
60
  */
@@ -42,17 +62,18 @@ export default class PlaySocket {
42
62
  #private;
43
63
  /**
44
64
  * Create a new PlaySocket instance
45
- * @param {string} [id] - Unique identifier for this client (assigned by the server if omitted)
65
+ * @param {string | null} [id] - Unique identifier for this client (assigned by the server if omitted or null)
46
66
  * @param {PlaySocketOptions} options - Connection options
47
67
  */
48
- constructor(id?: string, options?: PlaySocketOptions);
68
+ constructor(id?: string | null, options?: PlaySocketOptions);
49
69
  /**
50
70
  * Register an event callback
51
- * @param {string} event - Event name
52
- * @param {Function} callback - Callback function
53
- * @returns {Function} - Unsubscribe
71
+ * @template {keyof ClientEventMap} E
72
+ * @param {E} event - Event name
73
+ * @param {ClientEventMap[E]} callback - Callback function
74
+ * @returns {Function} Unsubscribe
54
75
  */
55
- onEvent(event: string, callback: Function): Function;
76
+ onEvent<E extends keyof ClientEventMap>(event: E, callback: ClientEventMap[E]): Function;
56
77
  /**
57
78
  * Initialize the PlaySocket instance by connecting to the WS server
58
79
  * @returns {Promise<string>} Resolves with the client ID when the connection is established
@@ -60,15 +81,15 @@ export default class PlaySocket {
60
81
  init(): Promise<string>;
61
82
  /**
62
83
  * Create a new room and become host
63
- * @param {object} [initialStorage] - Initial state
84
+ * @param {object | null} [initialStorage] - Initial state
64
85
  * @param {number} [size] - Max number of participants
65
86
  * @returns {Promise<string>} Resolves with room ID
66
87
  */
67
- createRoom(initialStorage?: object, size?: number): Promise<string>;
88
+ createRoom(initialStorage?: object | null, size?: number): Promise<string>;
68
89
  /**
69
90
  * Join an existing room
70
91
  * @param {string} roomId - ID of the room
71
- * @returns {Promise<void>} - Resolves when connected
92
+ * @returns {Promise<void>} Resolves when connected
72
93
  */
73
94
  joinRoom(roomId: string): Promise<void>;
74
95
  /**
@@ -83,7 +104,7 @@ export default class PlaySocket {
83
104
  * Send a custom request to the server
84
105
  * @param {string} name - Name of the request
85
106
  * @param {*} [data] - Custom data
86
- * @returns {Promise<void>} - Request promise
107
+ * @returns {Promise<void>} Request promise
87
108
  */
88
109
  sendRequest(name: string, data?: any): Promise<void>;
89
110
  /**
@@ -33,6 +33,39 @@ export type Room = {
33
33
  */
34
34
  crdtManager: CRDTManager;
35
35
  };
36
+ export type RejectViaStringOrBool = boolean | string | void;
37
+ export type ServerEventMap = {
38
+ clientRegistrationRequested: (clientId: string, customData: any) => RejectViaStringOrBool | Promise<RejectViaStringOrBool>;
39
+ clientRegistered: (clientId: string, customData: any) => void;
40
+ clientDisconnected: (clientId: string) => void;
41
+ clientJoinedRoom: (clientId: string, roomId: string) => void;
42
+ clientLeftRoom: (clientId: string, roomId: string) => void;
43
+ clientJoinRequested: (clientId: string, roomId: string) => RejectViaStringOrBool | Promise<RejectViaStringOrBool>;
44
+ roomCreated: (roomId: string) => void;
45
+ roomDestroyed: (roomId: string) => void;
46
+ roomCreationRequested: (payload: {
47
+ clientId: string;
48
+ initialStorage: Record<string, any>;
49
+ }) => Record<string, any> | RejectViaStringOrBool | Promise<Record<string, any> | RejectViaStringOrBool>;
50
+ requestReceived: (payload: {
51
+ roomId: string | null;
52
+ clientId: string;
53
+ name: string;
54
+ data: unknown;
55
+ }) => RejectViaStringOrBool | Promise<RejectViaStringOrBool>;
56
+ storageUpdateRequested: (payload: {
57
+ roomId: string;
58
+ clientId: string;
59
+ update: PropertyUpdate;
60
+ storage: Record<string, any> | undefined;
61
+ }) => RejectViaStringOrBool;
62
+ storageUpdated: (payload: {
63
+ roomId: string;
64
+ clientId: string | null;
65
+ update: PropertyUpdate;
66
+ storage: Record<string, any> | undefined;
67
+ }) => void;
68
+ };
36
69
  /**
37
70
  * @typedef {import("node:http").Server} HttpServer
38
71
  * @typedef {import("../universal/crdtManager.js").PropertyUpdateType} PropertyUpdateType
@@ -51,6 +84,23 @@ export type Room = {
51
84
  * @property {number} size - Max. number of participants
52
85
  * @property {CRDTManager} crdtManager - CRDT manager holding the room storage
53
86
  */
87
+ /** @typedef {boolean | string | void} RejectViaStringOrBool */
88
+ /**
89
+ * Event callback types
90
+ * @typedef {object} ServerEventMap
91
+ * @property {(clientId: string, customData: any) => RejectViaStringOrBool | Promise<RejectViaStringOrBool>} clientRegistrationRequested
92
+ * @property {(clientId: string, customData: any) => void} clientRegistered
93
+ * @property {(clientId: string) => void} clientDisconnected
94
+ * @property {(clientId: string, roomId: string) => void} clientJoinedRoom
95
+ * @property {(clientId: string, roomId: string) => void} clientLeftRoom
96
+ * @property {(clientId: string, roomId: string) => RejectViaStringOrBool | Promise<RejectViaStringOrBool>} clientJoinRequested
97
+ * @property {(roomId: string) => void} roomCreated
98
+ * @property {(roomId: string) => void} roomDestroyed
99
+ * @property {(payload: { clientId: string, initialStorage: Record<string, any> }) => Record<string, any> | RejectViaStringOrBool | Promise<Record<string, any> | RejectViaStringOrBool>} roomCreationRequested
100
+ * @property {(payload: { roomId: string | null, clientId: string, name: string, data: unknown }) => RejectViaStringOrBool | Promise<RejectViaStringOrBool>} requestReceived
101
+ * @property {(payload: { roomId: string, clientId: string, update: PropertyUpdate, storage: Record<string, any> | undefined }) => RejectViaStringOrBool} storageUpdateRequested
102
+ * @property {(payload: { roomId: string, clientId: string | null, update: PropertyUpdate, storage: Record<string, any> | undefined }) => void} storageUpdated
103
+ */
54
104
  /**
55
105
  * PlaySocket Server
56
106
  */
@@ -76,11 +126,12 @@ export default class PlaySocketServer {
76
126
  });
77
127
  /**
78
128
  * Register an event callback
79
- * @param {string} event - Event name
80
- * @param {Function} callback - Callback function
81
- * @returns {Function} - Unsubscribe
129
+ * @template {keyof ServerEventMap} E
130
+ * @param {E} event - Event name
131
+ * @param {ServerEventMap[E]} callback - Callback function
132
+ * @returns {Function} Unsubscribe
82
133
  */
83
- onEvent(event: string, callback: Function): Function;
134
+ onEvent<E extends keyof ServerEventMap>(event: E, callback: ServerEventMap[E]): Function;
84
135
  /**
85
136
  * Kick a client from the server
86
137
  * @param {string} clientId - Client ID
@@ -96,13 +147,13 @@ export default class PlaySocketServer {
96
147
  /**
97
148
  * Get snapshot of a room's storage
98
149
  * @param {string} roomId - ID of the room to get the storage from
99
- * @returns {Record<string, any> | undefined} - Storage object or undefined if the room doesn't exist
150
+ * @returns {Record<string, any> | undefined} Storage object or undefined if the room doesn't exist
100
151
  */
101
152
  getRoomStorage(roomId: string): Record<string, any> | undefined;
102
153
  /**
103
154
  * Get the operation details from a storage update (e.g. in the "storageUpdateRequested" event)
104
155
  * @param {PropertyUpdate} update - Property update
105
- * @returns {{key: string | undefined, type: PropertyUpdateType | undefined, value: *, secondValue: *}} - Operation details
156
+ * @returns {{key: string | undefined, type: PropertyUpdateType | undefined, value: *, secondValue: *}} Operation details
106
157
  */
107
158
  getUpdateDetails(update: PropertyUpdate): {
108
159
  key: string | undefined;
@@ -121,11 +172,11 @@ export default class PlaySocketServer {
121
172
  updateRoomStorage(roomId: string, key: string, type: PropertyUpdateType, value: any, secondValue?: any): void;
122
173
  /**
123
174
  * Create a server-owned room
124
- * @param {object} [initialStorage] - Optional initial storage object
175
+ * @param {object | null} [initialStorage] - Optional initial storage object
125
176
  * @param {number} [size] - Max. room size, up to 500
126
177
  * @returns {{ state: CRDTState, id: string }} Object containing room state and room ID
127
178
  */
128
- createRoom(initialStorage?: object, size?: number): {
179
+ createRoom(initialStorage?: object | null, size?: number): {
129
180
  state: CRDTState;
130
181
  id: string;
131
182
  };
@@ -8,7 +8,7 @@ export declare const HEARTBEAT_INTERVAL = 5000;
8
8
  /**
9
9
  * Library version, must match package.json
10
10
  */
11
- export declare const VERSION = "5.0.0";
11
+ export declare const VERSION = "5.1.0";
12
12
  /**
13
13
  * Logging prefixes
14
14
  */
@@ -115,29 +115,29 @@ export default class CRDTManager {
115
115
  * @param {PropertyUpdateType} type - Operation type
116
116
  * @param {*} value - Value
117
117
  * @param {*} [secondValue] - Second value (needed for some operations)
118
- * @returns {PropertyUpdate | undefined} - Returns the property update
118
+ * @returns {PropertyUpdate | undefined} Returns the property update
119
119
  */
120
120
  updateProperty(key: string, type: PropertyUpdateType, value: any, secondValue?: any): PropertyUpdate | undefined;
121
121
  /**
122
122
  * Get property store
123
- * @returns {Record<string, any>} - Object with key value pairs
123
+ * @returns {Record<string, any>} Object with key value pairs
124
124
  */
125
125
  get propertyStore(): Record<string, any>;
126
126
  /**
127
127
  * Check for changes in the local property store
128
- * @returns {boolean} - Check if any values changed going from the last to the current property update
128
+ * @returns {boolean} Check if any values changed going from the last to the current property update
129
129
  */
130
130
  get didPropertiesChange(): boolean;
131
131
  /**
132
132
  * Export state (can be imported using importState, converts the maps to arrays for serialization)
133
- * @returns {CRDTState} - State
133
+ * @returns {CRDTState} State
134
134
  */
135
135
  get state(): CRDTState;
136
136
  }
137
137
  /**
138
138
  * Get the operation details from a property update
139
139
  * @param {PropertyUpdate} update - Property update
140
- * @returns {{key: string | undefined, type: PropertyUpdateType | undefined, value: *, secondValue: *}} - Operation details
140
+ * @returns {{key: string | undefined, type: PropertyUpdateType | undefined, value: *, secondValue: *}} Operation details
141
141
  */
142
142
  export declare function getUpdateDetails(update: PropertyUpdate): {
143
143
  key: string | undefined;