playsocketjs 1.1.3 → 1.1.5

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,9 +1731,9 @@ 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
1738
  // Map operation uuids to timestamp
1739
1739
  this.#keyOperations.forEach((value, key) => {
@@ -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,26 +2279,14 @@ 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
2282
  case 'property_update':
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) {
2302
- this.#triggerEvent("error", "Detected missing update – requesting full state.");
2303
- this.#requestStateSync();
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();
2304
2290
  }
2305
2291
  break;
2306
2292
 
@@ -2371,28 +2357,6 @@ class PlaySocket {
2371
2357
  }
2372
2358
  }
2373
2359
 
2374
- /**
2375
- * If the local state is out of sync, request the room state
2376
- */
2377
- async #requestStateSync() {
2378
- if (this.#pendingStateRequest) return; // Return if already requested
2379
- try {
2380
- await Promise.race([
2381
- new Promise(async (resolve, reject) => {
2382
- this.#pendingStateRequest = { resolve, reject };
2383
- this.#sendToServer({ type: 'request_state' });
2384
- }),
2385
- this.#createTimeout("State request")
2386
- ]).finally(() => {
2387
- this.#pendingStateRequest = null;
2388
- });
2389
- } catch (error) {
2390
- if (!this.#initialized) return;
2391
- this.#triggerEvent("error", "Failed to re-sync state: " + error.message);
2392
- this.destroy();
2393
- }
2394
- }
2395
-
2396
2360
  /**
2397
2361
  * Update the host in case a new one was chosen
2398
2362
  * @param {string} hostId - Client id of new host
@@ -2410,7 +2374,7 @@ class PlaySocket {
2410
2374
  * @private
2411
2375
  */
2412
2376
  #sendToServer(data) {
2413
- if (!this.#socket || this.#socket.readyState !== WebSocket.OPEN) {
2377
+ if (!this.#socket || this.#socket?.readyState !== WebSocket.OPEN) {
2414
2378
  return console.warn(WARNING_PREFIX + "Cannot send message - not connected.");
2415
2379
  }
2416
2380
  try {
@@ -2491,20 +2455,11 @@ class PlaySocket {
2491
2455
  updateStorage(key, value) {
2492
2456
  if (this.#debug) console.log(LOG_PREFIX + "Property set update for key '" + key + "':", value);
2493
2457
  const propUpdate = this.#crdtManager.updateProperty(key, "set", value);
2494
- const updateUuid = crypto.randomUUID();
2495
- this.#sentUpdates.add(updateUuid);
2496
2458
  this.#sendToServer({
2497
2459
  type: 'property_update',
2498
2460
  key,
2499
- update: propUpdate,
2500
- uuid: updateUuid
2461
+ update: propUpdate
2501
2462
  });
2502
- setTimeout(() => {
2503
- if (this.#initialized && this.#sentUpdates.has(updateUuid)) {
2504
- this.#triggerEvent("error", "Sent update did not go through – requesting state.");
2505
- this.#requestStateSync();
2506
- }
2507
- }, TIMEOUT_MS);
2508
2463
  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)
2509
2464
  }
2510
2465
 
@@ -2518,20 +2473,11 @@ class PlaySocket {
2518
2473
  updateStorageArray(key, operation, value, updateValue) {
2519
2474
  if (this.#debug) console.log(LOG_PREFIX + `Property array update for key '${key}', operation '${operation}', value '${value}' and updateValue '${updateValue}'.`);
2520
2475
  const propUpdate = this.#crdtManager.updateProperty(key, "array-" + operation, value, updateValue);
2521
- const updateUuid = crypto.randomUUID();
2522
- this.#sentUpdates.add(updateUuid);
2523
2476
  this.#sendToServer({
2524
2477
  type: 'property_update',
2525
2478
  key,
2526
- update: propUpdate,
2527
- uuid: updateUuid
2479
+ update: propUpdate
2528
2480
  });
2529
- setTimeout(() => {
2530
- if (this.#initialized && this.#sentUpdates.has(updateUuid)) {
2531
- this.#triggerEvent("error", "Sent update did not go through – requesting state.");
2532
- this.#requestStateSync();
2533
- }
2534
- }, TIMEOUT_MS);
2535
2481
  if (this.#crdtManager.didPropertiesChange) this.#triggerEvent("storageUpdated", this.getStorage);
2536
2482
  }
2537
2483
 
@@ -2560,7 +2506,6 @@ class PlaySocket {
2560
2506
  this.#isReconnecting = false;
2561
2507
  this.#reconnectCount = 0;
2562
2508
  this.#roomVersion = 0;
2563
- this.#sentUpdates.clear();
2564
2509
 
2565
2510
  // Reject timeouts if currently active
2566
2511
  if (this.#pendingJoin) this.#pendingJoin.reject();
@@ -2568,7 +2513,6 @@ class PlaySocket {
2568
2513
  if (this.#pendingRegistration) this.#pendingRegistration.reject();
2569
2514
  if (this.#pendingConnect) this.#pendingConnect.reject();
2570
2515
  if (this.#pendingReconnect) this.#pendingReconnect.reject();
2571
- if (this.#pendingStateRequest) this.#pendingStateRequest.reject();
2572
2516
  }
2573
2517
 
2574
2518
  // Public getters
@@ -1857,9 +1857,9 @@ 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
1864
  // Map operation uuids to timestamp
1865
1865
  this.#keyOperations.forEach((value, key) => {
@@ -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;
@@ -2400,7 +2388,7 @@ function requireServer () {
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.key && data.update) {
2404
2392
  updateRoom.crdtManager.importPropertyUpdate(data.update);
2405
2393
 
2406
2394
  // Increment version for this room
@@ -2414,8 +2402,7 @@ function requireServer () {
2414
2402
  client.send(encode({
2415
2403
  type: 'property_update',
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.3",
3
+ "version": "1.1.5",
4
4
  "description": "WebSocket wrapper for creating simple multiplayer systems with ease.",
5
5
  "module": "dist/playsocket-client.js",
6
6
  "exports": {