playsocketjs 1.1.4 → 1.1.6

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.
@@ -1731,11 +1731,11 @@ function requireCrdtManager () {
1731
1731
  this.#propertyStore = {};
1732
1732
  this.#lastPropertyStore = {};
1733
1733
 
1734
- this.#keyOperations = new Map(keyOperations); // Rebuild the map
1735
- this.#vectorClock = new Map(vectorClock); // Also rebuild the map here
1736
- if (!this.#vectorClock.has(this.#replicaId)) this.#vectorClock.set(this.#replicaId, 0); // Reset own vector clock if it wasn't present in the imported state
1734
+ this.#keyOperations = new Map(keyOperations); // Rebuild the operations map
1735
+ this.#vectorClock = new Map(vectorClock); // Rebuild the vector clock map
1736
+ if (!this.#vectorClock.has(this.#replicaId)) this.#vectorClock.set(this.#replicaId, 0); // Add own vector clock if it wasn't present in the imported state
1737
1737
 
1738
- // Map operation uuids to timestamp
1738
+ // Map all operation uuids to current timestamp
1739
1739
  this.#keyOperations.forEach((value, key) => {
1740
1740
  value?.forEach((operation) => {
1741
1741
  this.#opUuidTimestamp.set(operation?.uuid, Date.now());
@@ -2065,7 +2065,6 @@ class PlaySocket {
2065
2065
  #connectionCount = 0;
2066
2066
  #crdtManager;
2067
2067
  #roomVersion = 0; // Update version (used to compare local vs. remote state to detect package loss)
2068
- #sentUpdates = new Set(); // Contains update uuids
2069
2068
 
2070
2069
  // Event handling
2071
2070
  #callbacks = new Map(); // Event callbacks
@@ -2076,7 +2075,6 @@ class PlaySocket {
2076
2075
  #pendingRegistration;
2077
2076
  #pendingConnect;
2078
2077
  #pendingReconnect;
2079
- #pendingStateRequest;
2080
2078
 
2081
2079
  // Timeouts or intervals
2082
2080
  #reconnectTimeout;
@@ -2281,24 +2279,15 @@ class PlaySocket {
2281
2279
  }
2282
2280
  break;
2283
2281
 
2284
- case 'state_sync':
2285
- if (this.#pendingStateRequest) {
2286
- if (this.#debug) console.log(LOG_PREFIX + "State received following state request:", message.state);
2287
- this.#roomVersion = message.version;
2288
- this.#crdtManager.importState(message.state);
2289
- this.#triggerEvent("storageUpdated", this.getStorage);
2290
- this.#triggerEvent("status", "State synchronized.");
2291
- this.#pendingStateRequest.resolve();
2292
- }
2293
- break;
2294
-
2295
- case 'property_update':
2282
+ case 'property_updated':
2296
2283
  this.#roomVersion++; // Increment room version
2297
2284
  if (this.#debug) console.log(LOG_PREFIX + "Property update received:", message.update);
2298
- this.#sentUpdates.delete(message.uuid); // If this is our sent update, delete it so that timeout check knows it was received
2299
2285
  this.#crdtManager.importPropertyUpdate(message.update);
2300
2286
  if (this.#crdtManager.didPropertiesChange) this.#triggerEvent("storageUpdated", this.getStorage);
2301
- if (this.#roomVersion != message.version) this.#requestStateSyncIfConnected();
2287
+ if (this.#roomVersion != message.version && this.#initialized && this.#socket?.readyState === WebSocket.OPEN) {
2288
+ this.#triggerEvent("error", "Detected skipped update – forcing reconnect.");
2289
+ this.#socket?.close();
2290
+ }
2302
2291
  break;
2303
2292
 
2304
2293
  case 'client_disconnected':
@@ -2368,33 +2357,6 @@ class PlaySocket {
2368
2357
  }
2369
2358
  }
2370
2359
 
2371
- /**
2372
- * If the local state is out of sync, request the room state
2373
- */
2374
- async #requestStateSyncIfConnected(notSent = false) {
2375
- if (this.#pendingStateRequest || !this.#initialized || this.#socket?.readyState !== WebSocket.OPEN) return; // Return if already requested, destroyed or connection not open
2376
-
2377
- // Trigger corresponding events
2378
- if (!notSent) this.#triggerEvent("error", "Detected skipped update – requesting state.");
2379
- else this.#triggerEvent("error", "Sent update did not go through – requesting state.");
2380
-
2381
- try {
2382
- await Promise.race([
2383
- new Promise(async (resolve, reject) => {
2384
- this.#pendingStateRequest = { resolve, reject };
2385
- this.#sendToServer({ type: 'request_state' });
2386
- }),
2387
- this.#createTimeout("State request")
2388
- ]).finally(() => {
2389
- this.#pendingStateRequest = null;
2390
- });
2391
- } catch (error) {
2392
- if (!this.#initialized) return;
2393
- this.#triggerEvent("error", "Failed to re-sync state: " + error.message);
2394
- this.destroy();
2395
- }
2396
- }
2397
-
2398
2360
  /**
2399
2361
  * Update the host in case a new one was chosen
2400
2362
  * @param {string} hostId - Client id of new host
@@ -2493,17 +2455,10 @@ class PlaySocket {
2493
2455
  updateStorage(key, value) {
2494
2456
  if (this.#debug) console.log(LOG_PREFIX + "Property set update for key '" + key + "':", value);
2495
2457
  const propUpdate = this.#crdtManager.updateProperty(key, "set", value);
2496
- const updateUuid = crypto.randomUUID();
2497
- this.#sentUpdates.add(updateUuid);
2498
2458
  this.#sendToServer({
2499
- type: 'property_update',
2500
- key,
2501
- update: propUpdate,
2502
- uuid: updateUuid
2459
+ type: 'update_property',
2460
+ update: propUpdate
2503
2461
  });
2504
- setTimeout(() => {
2505
- if (this.#sentUpdates.has(updateUuid)) this.#requestStateSyncIfConnected(true);
2506
- }, TIMEOUT_MS);
2507
2462
  if (this.#crdtManager.didPropertiesChange) this.#triggerEvent("storageUpdated", this.getStorage); // Always trigger callback after send in case msgs are sent in the callback (which would break the order)
2508
2463
  }
2509
2464
 
@@ -2517,17 +2472,10 @@ class PlaySocket {
2517
2472
  updateStorageArray(key, operation, value, updateValue) {
2518
2473
  if (this.#debug) console.log(LOG_PREFIX + `Property array update for key '${key}', operation '${operation}', value '${value}' and updateValue '${updateValue}'.`);
2519
2474
  const propUpdate = this.#crdtManager.updateProperty(key, "array-" + operation, value, updateValue);
2520
- const updateUuid = crypto.randomUUID();
2521
- this.#sentUpdates.add(updateUuid);
2522
2475
  this.#sendToServer({
2523
- type: 'property_update',
2524
- key,
2525
- update: propUpdate,
2526
- uuid: updateUuid
2476
+ type: 'update_property',
2477
+ update: propUpdate
2527
2478
  });
2528
- setTimeout(() => {
2529
- if (this.#sentUpdates.has(updateUuid)) this.#requestStateSyncIfConnected(true);
2530
- }, TIMEOUT_MS);
2531
2479
  if (this.#crdtManager.didPropertiesChange) this.#triggerEvent("storageUpdated", this.getStorage);
2532
2480
  }
2533
2481
 
@@ -2556,7 +2504,6 @@ class PlaySocket {
2556
2504
  this.#isReconnecting = false;
2557
2505
  this.#reconnectCount = 0;
2558
2506
  this.#roomVersion = 0;
2559
- this.#sentUpdates.clear();
2560
2507
 
2561
2508
  // Reject timeouts if currently active
2562
2509
  if (this.#pendingJoin) this.#pendingJoin.reject();
@@ -2564,7 +2511,6 @@ class PlaySocket {
2564
2511
  if (this.#pendingRegistration) this.#pendingRegistration.reject();
2565
2512
  if (this.#pendingConnect) this.#pendingConnect.reject();
2566
2513
  if (this.#pendingReconnect) this.#pendingReconnect.reject();
2567
- if (this.#pendingStateRequest) this.#pendingStateRequest.reject();
2568
2514
  }
2569
2515
 
2570
2516
  // Public getters
@@ -1857,11 +1857,11 @@ function requireCrdtManager () {
1857
1857
  this.#propertyStore = {};
1858
1858
  this.#lastPropertyStore = {};
1859
1859
 
1860
- this.#keyOperations = new Map(keyOperations); // Rebuild the map
1861
- this.#vectorClock = new Map(vectorClock); // Also rebuild the map here
1862
- if (!this.#vectorClock.has(this.#replicaId)) this.#vectorClock.set(this.#replicaId, 0); // Reset own vector clock if it wasn't present in the imported state
1860
+ this.#keyOperations = new Map(keyOperations); // Rebuild the operations map
1861
+ this.#vectorClock = new Map(vectorClock); // Rebuild the vector clock map
1862
+ if (!this.#vectorClock.has(this.#replicaId)) this.#vectorClock.set(this.#replicaId, 0); // Add own vector clock if it wasn't present in the imported state
1863
1863
 
1864
- // Map operation uuids to timestamp
1864
+ // Map all operation uuids to current timestamp
1865
1865
  this.#keyOperations.forEach((value, key) => {
1866
1866
  value?.forEach((operation) => {
1867
1867
  this.#opUuidTimestamp.set(operation?.uuid, Date.now());
@@ -2239,7 +2239,7 @@ function requireServer () {
2239
2239
  ws.isAlive = false;
2240
2240
  ws.ping();
2241
2241
  });
2242
- }, 30000);
2242
+ }, 15000);
2243
2243
  }
2244
2244
 
2245
2245
  /**
@@ -2309,18 +2309,6 @@ function requireServer () {
2309
2309
  }
2310
2310
  break;
2311
2311
 
2312
- case 'request_state':
2313
- const stateRoomId = this.#clientRooms.get(ws.clientId);
2314
- const stateRoom = stateRoomId ? this.#rooms[stateRoomId] : null;
2315
- if (stateRoom) {
2316
- ws.send(encode({
2317
- type: 'state_sync',
2318
- state: stateRoom.crdtManager.getState,
2319
- version: this.#roomVersions.get(stateRoomId)
2320
- }), { binary: true });
2321
- }
2322
- break;
2323
-
2324
2312
  case 'create_room':
2325
2313
  if (!ws.clientId) return;
2326
2314
  const newRoomId = ws.clientId;
@@ -2396,11 +2384,11 @@ function requireServer () {
2396
2384
  this.#triggerEvent("roomJoined", ws.clientId, roomId);
2397
2385
  break;
2398
2386
 
2399
- case 'property_update':
2387
+ case 'update_property':
2400
2388
  const updateRoomId = this.#clientRooms.get(ws.clientId);
2401
2389
  const updateRoom = updateRoomId ? this.#rooms[updateRoomId] : null;
2402
2390
 
2403
- if (updateRoom && data.key && data.update && data.uuid) {
2391
+ if (updateRoom && data.update) {
2404
2392
  updateRoom.crdtManager.importPropertyUpdate(data.update);
2405
2393
 
2406
2394
  // Increment version for this room
@@ -2412,10 +2400,9 @@ function requireServer () {
2412
2400
  const client = this.#clients.get(p);
2413
2401
  if (client) {
2414
2402
  client.send(encode({
2415
- type: 'property_update',
2403
+ type: 'property_updated',
2416
2404
  update: data.update,
2417
- version: currentVersion,
2418
- uuid: data.uuid
2405
+ version: currentVersion
2419
2406
  }), { binary: true });
2420
2407
  }
2421
2408
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playsocketjs",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "WebSocket wrapper for creating simple multiplayer systems with ease.",
5
5
  "module": "dist/playsocket-client.js",
6
6
  "exports": {