playsocketjs 5.1.0 → 5.2.1
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 +1 -1
- package/package.json +1 -1
- package/src/server/server.js +5 -3
- package/src/universal/constants.js +1 -1
- package/src/universal/crdtManager.js +23 -20
- package/types/server/server.d.ts +6 -2
- package/types/universal/constants.d.ts +1 -1
- package/types/universal/crdtManager.d.ts +5 -0
package/README.md
CHANGED
|
@@ -315,7 +315,7 @@ The callback signature is `callback(verified, code?, message?)` where `code` ref
|
|
|
315
315
|
| `kick()` | `clientId: string, reason?: string` | `void` | Kick a client by their client ID. |
|
|
316
316
|
| `move()` | `clientId: string, roomId: string` | `void` | Move a client that is already in a room to a different room. |
|
|
317
317
|
| `onEvent()` | `event: string, callback: Function` | `() => void` | Register a server-side event callback. Returns unsubscribe function. |
|
|
318
|
-
| `getRoomStorage()` | `roomId: string` | `object` | Get a snapshot of the current room storage. |
|
|
318
|
+
| `getRoomStorage()` | `roomId: string, options?: { dangerouslySkipCloning?: boolean }` | `object` | Get a snapshot of the current room storage. Pass `dangerouslySkipCloning: true` to get the uncloned store for performance reasons. |
|
|
319
319
|
| `getUpdateDetails()` | `update: object` | `object` | Get the details (`key`, `type`, `value` and `secondValue`) of a storage update for building validation logic. |
|
|
320
320
|
| `updateRoomStorage()` | `roomId: string, key: string, type: string, value: any, secondValue?: any` | `void` | Update a key in the shared storage of a room. |
|
|
321
321
|
| `createRoom()` | `initialStorage?: object, size?: number` | `object` | Create a server-owned room (returns object containing room ID and state).|
|
package/package.json
CHANGED
package/src/server/server.js
CHANGED
|
@@ -576,13 +576,15 @@ export default class PlaySocketServer {
|
|
|
576
576
|
}
|
|
577
577
|
|
|
578
578
|
/**
|
|
579
|
-
* Get snapshot of a room's storage
|
|
579
|
+
* Get a snapshot of a room's storage
|
|
580
580
|
* @param {string} roomId - ID of the room to get the storage from
|
|
581
|
+
* @param {object} [options] - Options
|
|
582
|
+
* @param {boolean} [options.dangerouslySkipCloning=false] - Return uncloned store (faster, but allows illegal mutation)
|
|
581
583
|
* @returns {Record<string, any> | undefined} Storage object or undefined if the room doesn't exist
|
|
582
584
|
*/
|
|
583
|
-
getRoomStorage(roomId) {
|
|
585
|
+
getRoomStorage(roomId, { dangerouslySkipCloning = false } = {}) {
|
|
584
586
|
const room = this.#rooms[roomId];
|
|
585
|
-
if (room) return room.crdtManager.propertyStore;
|
|
587
|
+
if (room) return dangerouslySkipCloning ? room.crdtManager.rawPropertyStore : room.crdtManager.propertyStore;
|
|
586
588
|
}
|
|
587
589
|
|
|
588
590
|
/**
|
|
@@ -110,7 +110,7 @@ export default class CRDTManager {
|
|
|
110
110
|
importPropertyUpdate(update) {
|
|
111
111
|
try {
|
|
112
112
|
const { key, operation: rawOperation, vectorClock } = update;
|
|
113
|
-
const operation = /** @type {Operation} */ (this.#
|
|
113
|
+
const operation = /** @type {Operation} */ (this.#normalizeAndCopy(rawOperation));
|
|
114
114
|
if (this.#debug) console.log(CONSOLE_PREFIX + "Importing update:", update); // Debug
|
|
115
115
|
|
|
116
116
|
// Check key limit to safeguard against too many keys
|
|
@@ -183,9 +183,9 @@ export default class CRDTManager {
|
|
|
183
183
|
*/
|
|
184
184
|
updateProperty(key, type, value, secondValue) {
|
|
185
185
|
try {
|
|
186
|
-
//
|
|
187
|
-
value = this.#
|
|
188
|
-
secondValue = this.#
|
|
186
|
+
// Normalize inputs
|
|
187
|
+
value = this.#normalizeAndCopy(value);
|
|
188
|
+
secondValue = this.#normalizeAndCopy(secondValue);
|
|
189
189
|
|
|
190
190
|
// Debug log
|
|
191
191
|
if (this.#debug) console.log(CONSOLE_PREFIX + `Updating property with key ${key}, type ${type}, value ${value} and secondValue ${secondValue}`);
|
|
@@ -366,12 +366,12 @@ export default class CRDTManager {
|
|
|
366
366
|
*/
|
|
367
367
|
#handleOperation(curValue, type, value, secondValue) {
|
|
368
368
|
try {
|
|
369
|
+
// Set operation (before the structured clone since for set we don't care about curValue anyway)
|
|
370
|
+
if (type === "set") return value;
|
|
371
|
+
|
|
369
372
|
// Deep copy to avoid reference issues in case value is or contains object(s)
|
|
370
373
|
curValue = structuredClone(curValue);
|
|
371
374
|
|
|
372
|
-
// Set operation
|
|
373
|
-
if (type === "set") return value;
|
|
374
|
-
|
|
375
375
|
// Number increment operation
|
|
376
376
|
if (type === "number-increment") {
|
|
377
377
|
if (!Number.isFinite(curValue)) curValue = 0; // Auto-convert to number if current value isn't a finite number
|
|
@@ -431,20 +431,15 @@ export default class CRDTManager {
|
|
|
431
431
|
}
|
|
432
432
|
|
|
433
433
|
/**
|
|
434
|
-
*
|
|
435
|
-
* @param {*} value - Value to
|
|
436
|
-
* @returns {*}
|
|
434
|
+
* Enforce size limit, normalize undefined to null, and return deep copy
|
|
435
|
+
* @param {*} value - Value to normalize
|
|
436
|
+
* @returns {*} Normalized value
|
|
437
437
|
*/
|
|
438
|
-
#
|
|
439
|
-
if (value === undefined) return null;
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
if (jsonString?.length > 50000) throw new Error("Value too large"); // 50KB limit
|
|
444
|
-
|
|
445
|
-
if (typeof value === "string") return (value.includes("<") || value.includes(">")) ? value.replace(/[<>]/g, "") : value;
|
|
446
|
-
if (Array.isArray(value)) return Array.from(value, item => this.#sanitizeValue(item));
|
|
447
|
-
if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, this.#sanitizeValue(v)]));
|
|
438
|
+
#normalizeAndCopy(value) {
|
|
439
|
+
if (value === undefined) return null;
|
|
440
|
+
if (JSON.stringify(value)?.length > 50_000) throw new Error("Value too large"); // 50KB limit
|
|
441
|
+
if (Array.isArray(value)) return Array.from(value, item => this.#normalizeAndCopy(item));
|
|
442
|
+
if (value && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, this.#normalizeAndCopy(v)]));
|
|
448
443
|
return value;
|
|
449
444
|
}
|
|
450
445
|
|
|
@@ -461,6 +456,14 @@ export default class CRDTManager {
|
|
|
461
456
|
}
|
|
462
457
|
}
|
|
463
458
|
|
|
459
|
+
/**
|
|
460
|
+
* Get uncloned property store
|
|
461
|
+
* @returns {Record<string, any>} Object with key value pairs
|
|
462
|
+
*/
|
|
463
|
+
get rawPropertyStore() {
|
|
464
|
+
return this.#propertyStore;
|
|
465
|
+
}
|
|
466
|
+
|
|
464
467
|
/**
|
|
465
468
|
* Check for changes in the local property store
|
|
466
469
|
* @returns {boolean} Check if any values changed going from the last to the current property update
|
package/types/server/server.d.ts
CHANGED
|
@@ -145,11 +145,15 @@ export default class PlaySocketServer {
|
|
|
145
145
|
*/
|
|
146
146
|
move(clientId: string, roomId: string): void;
|
|
147
147
|
/**
|
|
148
|
-
* Get snapshot of a room's storage
|
|
148
|
+
* Get a snapshot of a room's storage
|
|
149
149
|
* @param {string} roomId - ID of the room to get the storage from
|
|
150
|
+
* @param {object} [options] - Options
|
|
151
|
+
* @param {boolean} [options.dangerouslySkipCloning=false] - Return uncloned store (faster, but allows illegal mutation)
|
|
150
152
|
* @returns {Record<string, any> | undefined} Storage object or undefined if the room doesn't exist
|
|
151
153
|
*/
|
|
152
|
-
getRoomStorage(roomId: string
|
|
154
|
+
getRoomStorage(roomId: string, { dangerouslySkipCloning }?: {
|
|
155
|
+
dangerouslySkipCloning?: boolean;
|
|
156
|
+
}): Record<string, any> | undefined;
|
|
153
157
|
/**
|
|
154
158
|
* Get the operation details from a storage update (e.g. in the "storageUpdateRequested" event)
|
|
155
159
|
* @param {PropertyUpdate} update - Property update
|
|
@@ -123,6 +123,11 @@ export default class CRDTManager {
|
|
|
123
123
|
* @returns {Record<string, any>} Object with key value pairs
|
|
124
124
|
*/
|
|
125
125
|
get propertyStore(): Record<string, any>;
|
|
126
|
+
/**
|
|
127
|
+
* Get uncloned property store
|
|
128
|
+
* @returns {Record<string, any>} Object with key value pairs
|
|
129
|
+
*/
|
|
130
|
+
get rawPropertyStore(): Record<string, any>;
|
|
126
131
|
/**
|
|
127
132
|
* Check for changes in the local property store
|
|
128
133
|
* @returns {boolean} Check if any values changed going from the last to the current property update
|