playsocketjs 2.5.1 → 2.5.3

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.
@@ -1,5 +1,5 @@
1
1
  import { WebSocketServer } from 'ws';
2
- import * as http from 'node:http';
2
+ import { createServer } from 'node:http';
3
3
 
4
4
  function utf8Count(str) {
5
5
  const strLength = str.length;
@@ -1686,13 +1686,15 @@ function decode(buffer, options) {
1686
1686
 
1687
1687
  const CONSOLE_PREFIX = "PlaySocket CRDT manager: ";
1688
1688
 
1689
+ /**
1690
+ * CRDT Manager
1691
+ */
1689
1692
  class CRDTManager {
1690
1693
  // Storage
1691
1694
  #replicaId;
1692
1695
  #keyOperations = new Map();
1693
1696
  #vectorClock = new Map();
1694
1697
 
1695
- // Local only
1696
1698
  #propertyStore = {}; // Current local values per key, as object
1697
1699
  #lastPropertyStore = {}; // Last property store to compare against
1698
1700
 
@@ -1705,6 +1707,7 @@ class CRDTManager {
1705
1707
 
1706
1708
  /**
1707
1709
  * Create a new instance
1710
+ * @param {boolean} [debug=false] - Enable debug logging
1708
1711
  */
1709
1712
  constructor(debug) {
1710
1713
  if (debug) this.#debug = true;
@@ -1714,7 +1717,7 @@ class CRDTManager {
1714
1717
 
1715
1718
  /**
1716
1719
  * Import the entire state of the CRDT manager (this overwrites the old state)
1717
- * @param {Object} state
1720
+ * @param {object} state - Full state of the CRDT manager
1718
1721
  */
1719
1722
  importState(state) {
1720
1723
  try {
@@ -1731,7 +1734,7 @@ class CRDTManager {
1731
1734
  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
1732
1735
 
1733
1736
  // Map all operation uuids to current timestamp
1734
- this.#keyOperations.forEach((value, key) => {
1737
+ this.#keyOperations.forEach((value, _key) => {
1735
1738
  value?.forEach((operation) => {
1736
1739
  this.#opUuidTimestamp.set(operation?.uuid, Date.now());
1737
1740
  });
@@ -1747,7 +1750,7 @@ class CRDTManager {
1747
1750
 
1748
1751
  /**
1749
1752
  * Import property update
1750
- * @param {Object} data - Data to import
1753
+ * @param {object} data - Property update data
1751
1754
  */
1752
1755
  importPropertyUpdate(data) {
1753
1756
  try {
@@ -1789,11 +1792,11 @@ class CRDTManager {
1789
1792
 
1790
1793
  /**
1791
1794
  * Update a property
1792
- * @param {string} key
1793
- * @param {string} type
1794
- * @param {*} value
1795
- * @param {*} updateValue
1796
- * @returns {Object} - Returns the property update
1795
+ * @param {string} key - Storage key
1796
+ * @param {string} type - Operation type
1797
+ * @param {*} value - New value, or value to match
1798
+ * @param {*} updateValue - New value for 'matching' operations
1799
+ * @returns {object | undefined} - Returns the property update
1797
1800
  */
1798
1801
  updateProperty(key, type, value, updateValue) {
1799
1802
  try {
@@ -1830,6 +1833,9 @@ class CRDTManager {
1830
1833
  }
1831
1834
  }
1832
1835
 
1836
+ /**
1837
+ * Check if garbage collected can be performed & run it
1838
+ */
1833
1839
  #checkGarbageCollection() {
1834
1840
  const MIN_GC_DELAY = 1000; // Minimum 1s delay between garbage collection runs
1835
1841
  const MIN_AGE_FOR_GC = 5000; // Garbage collect ops that are older than 5s
@@ -1855,7 +1861,7 @@ class CRDTManager {
1855
1861
  if (this.#debug) console.log(CONSOLE_PREFIX + `Running garbage collection for key ${key} with current operations:`, operations);
1856
1862
  const retainOps = operations.slice(-retainCount); // Newest ops
1857
1863
  const removeOps = operations.slice(0, -retainCount); // Oldest ops (start = idx 0, end = retainCount counted from right side)
1858
- const baselineVectorClock = removeOps[removeOps.length - 1]?.vectorClock || []; // Use the vector clock from the last operation that we remove/overwrite
1864
+ const baselineVectorClock = removeOps[removeOps.length - 1]?.vectorClock || []; // Use the vector clock from the last operation that we remove/overwrite
1859
1865
 
1860
1866
  // Calculate the value at the point where retained operations start
1861
1867
  let baselineValue = null;
@@ -1886,9 +1892,9 @@ class CRDTManager {
1886
1892
 
1887
1893
  /**
1888
1894
  * Create an operation object
1889
- * @param {Object} data
1890
- * @param {Array} vectorClock
1891
- * @returns {Object} - Operation object
1895
+ * @param {object} data - Operation data, consists of type, value and updateValue
1896
+ * @param {Array} vectorClock - Vector clock of the replica/client
1897
+ * @returns {object} - Operation object
1892
1898
  */
1893
1899
  #createOperation(data, vectorClock) {
1894
1900
  const newOperation = {
@@ -1903,7 +1909,7 @@ class CRDTManager {
1903
1909
 
1904
1910
  /**
1905
1911
  * Process a property's value by applying all operations and set it in the property store
1906
- * @param {string} key
1912
+ * @param {string} key - Storage key
1907
1913
  */
1908
1914
  #processLocalProperty(key) {
1909
1915
  try {
@@ -1930,8 +1936,8 @@ class CRDTManager {
1930
1936
  }
1931
1937
 
1932
1938
  /**
1933
- * Sort by vector clock (causal order)
1934
- * @param {Array} operations
1939
+ * Sort operations by vector clock (causal order)
1940
+ * @param {Array} operations - Full operations that include vector clocks, data and a source
1935
1941
  * @returns {Array} - Sorted operations
1936
1942
  */
1937
1943
  #sortByVectorClock(operations) {
@@ -1967,10 +1973,10 @@ class CRDTManager {
1967
1973
 
1968
1974
  /**
1969
1975
  * Handle an operation
1970
- * @param {*} curValue
1971
- * @param {string} type
1972
- * @param {*} value
1973
- * @param {*} [updateValue]
1976
+ * @param {*} curValue - Current value of the storage key
1977
+ * @param {string} type - Operation type
1978
+ * @param {*} value - New value, or value to match
1979
+ * @param {*} [updateValue] - New value for 'matching' operations
1974
1980
  * @returns {*} - Value after the operation
1975
1981
  */
1976
1982
  #handleOperation(curValue, type, value, updateValue) {
@@ -2002,10 +2008,11 @@ class CRDTManager {
2002
2008
  case 'array-remove-matching':
2003
2009
  curValue = curValue.filter(item => !compare(item));
2004
2010
  break;
2005
- case 'array-update-matching':
2011
+ case 'array-update-matching': {
2006
2012
  const index = curValue.findIndex(compare);
2007
2013
  if (index !== -1) curValue[index] = updateValue;
2008
2014
  break;
2015
+ }
2009
2016
  }
2010
2017
  }
2011
2018
 
@@ -2019,42 +2026,53 @@ class CRDTManager {
2019
2026
 
2020
2027
  /**
2021
2028
  * Remove HTML to prevent XSS and enforce size limits
2022
- * @param {Object} obj
2023
- * @returns {Object} - Sanitized object
2029
+ * @param {*} value - Value to sanitize
2030
+ * @returns {*} - Sanitized value
2024
2031
  */
2025
- #sanitizeValue(obj) {
2032
+ #sanitizeValue(value) {
2026
2033
  // Check total serialized size
2027
- const jsonString = JSON.stringify(obj);
2034
+ const jsonString = JSON.stringify(value);
2028
2035
  if (jsonString?.length > 50000) throw new Error('Value too large!'); // 50KB limit
2029
2036
 
2030
- if (typeof obj === 'string') return (obj.includes('<') || obj.includes('>')) ? obj.replace(/[<>]/g, '') : obj;
2031
- if (Array.isArray(obj)) return obj.map(item => this.#sanitizeValue(item));
2032
- if (obj && typeof obj === 'object') return Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, this.#sanitizeValue(v)]));
2033
- return obj;
2037
+ if (typeof value === 'string') return (value.includes('<') || value.includes('>')) ? value.replace(/[<>]/g, '') : value;
2038
+ if (Array.isArray(value)) return value.map(item => this.#sanitizeValue(item));
2039
+ if (value && typeof value === 'object') return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, this.#sanitizeValue(v)]));
2040
+ return value;
2034
2041
  }
2035
2042
 
2036
- // Get property store
2043
+ /**
2044
+ * Get property store
2045
+ * @returns {Record<string, any>} - Object with key value pairs
2046
+ */
2037
2047
  get getPropertyStore() {
2038
2048
  try {
2039
2049
  return structuredClone(this.#propertyStore); // Return deep clone
2040
2050
  } catch {
2041
2051
  console.error(CONSOLE_PREFIX + "Failed to parse property store");
2042
- return {};
2052
+ return {}
2043
2053
  }
2044
2054
  }
2045
2055
 
2046
- // Check for changes in the local property store
2056
+ /**
2057
+ * Check for changes in the local property store
2058
+ * @returns {boolean} - Check if any values changed going from the last to the current property update
2059
+ */
2047
2060
  get didPropertiesChange() {
2048
2061
  try {
2049
2062
  if (JSON.stringify(this.#propertyStore) !== JSON.stringify(this.#lastPropertyStore)) {
2050
2063
  this.#lastPropertyStore = structuredClone(this.#propertyStore);
2051
2064
  return true;
2052
2065
  }
2053
- } catch { }
2066
+ } catch {
2067
+ console.error(CONSOLE_PREFIX + "Failed to stringify and compare property stores");
2068
+ }
2054
2069
  return false;
2055
2070
  }
2056
2071
 
2057
- // Get state (can be imported using importState, converts the maps to arrays for serialization)
2072
+ /**
2073
+ * Export state (can be imported using importState, converts the maps to arrays for serialization)
2074
+ * @returns {object} - State
2075
+ */
2058
2076
  get getState() {
2059
2077
  return {
2060
2078
  keyOperations: [...this.#keyOperations.entries()],
@@ -2063,8 +2081,15 @@ class CRDTManager {
2063
2081
  }
2064
2082
  }
2065
2083
 
2084
+ /* eslint-disable jsdoc/require-returns */
2085
+
2086
+ /**
2087
+ * @typedef {import('node:http').Server} HttpServer
2088
+ * @typedef {import('ws').WebSocket} WebSocket
2089
+ */
2090
+
2066
2091
  /**
2067
- * PlaySocketServer - WebSocket server for PlaySocket multiplayer library
2092
+ * PlaySocket Server
2068
2093
  */
2069
2094
  class PlaySocketServer {
2070
2095
  #server;
@@ -2086,10 +2111,12 @@ class PlaySocketServer {
2086
2111
 
2087
2112
  /**
2088
2113
  * Create a new PlaySocketServer instance
2089
- * @param {Object} options - Server configuration options
2114
+ * @param {object} options - Server configuration options
2090
2115
  * @param {HttpServer} [options.server] - Existing http server
2091
2116
  * @param {number} [options.port=3000] - Port to listen on (if no server provided)
2092
- * @param {string} [options.path='/socket'] - WebSocket endpoint path
2117
+ * @param {string} [options.path='/'] - WebSocket endpoint path
2118
+ * @param {boolean} [options.debug=false] - Enable debug logging
2119
+ * @param {number} [options.rateLimit=20] - Maximum number of operations per second per client
2093
2120
  */
2094
2121
  constructor(options = {}) {
2095
2122
  const { server, port = 3000, path = '/', debug = false, rateLimit = 20 } = options;
@@ -2103,7 +2130,7 @@ class PlaySocketServer {
2103
2130
  this.#server = server; // Use provided HTTP server
2104
2131
  } else {
2105
2132
  this.#ownsServer = true;
2106
- this.#server = http.createServer(); // Create HTTP server and start it
2133
+ this.#server = createServer(); // Create HTTP server and start it
2107
2134
  this.#server.listen(port, () => {
2108
2135
  console.log(`PlaySocket server running on port ${port}.`);
2109
2136
  });
@@ -2144,6 +2171,8 @@ class PlaySocketServer {
2144
2171
 
2145
2172
  /**
2146
2173
  * Handle WebSocket message
2174
+ * @param {WebSocket} ws - WebSocket client
2175
+ * @param {Buffer} message - Message encoded with messagepack
2147
2176
  * @private
2148
2177
  */
2149
2178
  async #handleMessage(ws, message) {
@@ -2156,12 +2185,13 @@ class PlaySocketServer {
2156
2185
  if (!ws.isTerminating) {
2157
2186
  ws.isTerminating = true; // Prevent multiple terminate calls (it is async)
2158
2187
  ws.terminate();
2159
- return console.error(`Connection ${ws.connectionId} terminated due to rate limit violations.`);
2188
+ console.error(`Connection ${ws.connectionId} terminated due to rate limit violations.`);
2189
+ return;
2160
2190
  }
2161
2191
  }
2162
2192
 
2163
2193
  switch (data.type) {
2164
- case 'register':
2194
+ case 'register': {
2165
2195
  // Register client ID if provided & check for a duplicate
2166
2196
  if (data.id && this.#clients.get(data.id)) {
2167
2197
  ws.send(encode({ type: 'registration_failed', reason: 'ID is taken.' }), { binary: true });
@@ -2200,8 +2230,9 @@ class PlaySocketServer {
2200
2230
  ws.send(encode({ type: 'registered', id: data.id, sessionToken }), { binary: true });
2201
2231
  this.#triggerEvent("clientRegistered", data.id, data.customData);
2202
2232
  break;
2233
+ }
2203
2234
 
2204
- case 'reconnect':
2235
+ case 'reconnect': {
2205
2236
  // If user is pending disconnect, respond (otherwise it's too late)
2206
2237
  const pd = this.#pendingDisconnects.get(data.id);
2207
2238
  if (pd && data.sessionToken) {
@@ -2238,8 +2269,9 @@ class PlaySocketServer {
2238
2269
  ws.send(encode({ type: 'reconnection_failed', reason: "Client unknown to server." }), { binary: true });
2239
2270
  }
2240
2271
  break;
2272
+ }
2241
2273
 
2242
- case 'create_room':
2274
+ case 'create_room': {
2243
2275
  if (!ws.clientId) return;
2244
2276
 
2245
2277
  let newRoomId;
@@ -2307,8 +2339,9 @@ class PlaySocketServer {
2307
2339
  this.#triggerEvent("roomCreated", newRoomId);
2308
2340
  if (this.#debug) console.log(`Room ${newRoomId} created with initial storage:`, data.initialStorage);
2309
2341
  break;
2342
+ }
2310
2343
 
2311
- case 'join_room':
2344
+ case 'join_room': {
2312
2345
  if (!data.roomId || !ws.clientId) return;
2313
2346
  const roomId = data.roomId;
2314
2347
  const room = this.#rooms[roomId];
@@ -2352,29 +2385,30 @@ class PlaySocketServer {
2352
2385
  });
2353
2386
  this.#triggerEvent("clientJoinedRoom", ws.clientId, roomId);
2354
2387
  break;
2388
+ }
2355
2389
 
2356
- case 'update_property':
2357
- const updateRoomId = this.#clientRooms.get(ws.clientId);
2358
- const updateRoom = updateRoomId ? this.#rooms[updateRoomId] : null;
2390
+ case 'update_property': {
2391
+ const roomId = this.#clientRooms.get(ws.clientId);
2392
+ const room = roomId ? this.#rooms[roomId] : null;
2359
2393
 
2360
- if (updateRoom && data.update) {
2394
+ if (room && data.update) {
2361
2395
  // Check if update is allowed via event callback (provide clone to ensure update integrity)
2362
- const updateAllowed = await this.#triggerEvent("storageUpdateRequested", { roomId: updateRoomId, clientId: ws.clientId, update: structuredClone(data.update) });
2396
+ const updateAllowed = await this.#triggerEvent("storageUpdateRequested", { roomId, clientId: ws.clientId, update: structuredClone(data.update) });
2363
2397
  if (updateAllowed === false) {
2364
2398
  ws.send(encode({
2365
2399
  type: 'property_update_rejected',
2366
- state: updateRoom.crdtManager.getState
2400
+ state: room.crdtManager.getState
2367
2401
  }), { binary: true });
2368
2402
  return;
2369
2403
  }
2370
2404
 
2371
- updateRoom.crdtManager.importPropertyUpdate(data.update); // Import update into server state
2405
+ room.crdtManager.importPropertyUpdate(data.update); // Import update into server state
2372
2406
 
2373
2407
  // Increment version for this room
2374
- const currentVersion = this.#roomVersions.get(updateRoomId) + 1;
2375
- this.#roomVersions.set(updateRoomId, currentVersion);
2408
+ const currentVersion = this.#roomVersions.get(roomId) + 1;
2409
+ this.#roomVersions.set(roomId, currentVersion);
2376
2410
 
2377
- updateRoom.participants?.forEach(p => {
2411
+ room.participants?.forEach(p => {
2378
2412
  const client = this.#clients.get(p);
2379
2413
  if (client) {
2380
2414
  client.send(encode({
@@ -2385,16 +2419,18 @@ class PlaySocketServer {
2385
2419
  }
2386
2420
  });
2387
2421
 
2388
- this.#triggerEvent("storageUpdated", { roomId: updateRoomId, clientId: ws.clientId, update: structuredClone(data.update), storage: this.getRoomStorage(updateRoomId) });
2422
+ this.#triggerEvent("storageUpdated", { roomId, clientId: ws.clientId, update: structuredClone(data.update), storage: this.getRoomStorage(roomId) });
2389
2423
  if (this.#debug) console.log("Property update received and imported:", data.update);
2390
2424
  }
2391
2425
  break;
2426
+ }
2392
2427
 
2393
- case 'request':
2428
+ case 'request': {
2394
2429
  if (!ws.clientId) return;
2395
- const requestorRoomId = this.#clientRooms.get(ws.clientId) || null;
2396
- this.#triggerEvent("requestReceived", { roomId: requestorRoomId, clientId: ws.clientId, name: data.request.name, data: data.request.data });
2430
+ const roomId = this.#clientRooms.get(ws.clientId) || null;
2431
+ this.#triggerEvent("requestReceived", { roomId, clientId: ws.clientId, name: data.request.name, data: data.request.data });
2397
2432
  break;
2433
+ }
2398
2434
 
2399
2435
  case 'disconnect':
2400
2436
  // Client signals to server that it will will willfully disconnect soon
@@ -2408,6 +2444,7 @@ class PlaySocketServer {
2408
2444
 
2409
2445
  /**
2410
2446
  * Generate a readable, 6 digit ID
2447
+ * @returns {string} - Id
2411
2448
  */
2412
2449
  #generateId() {
2413
2450
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789';
@@ -2417,8 +2454,8 @@ class PlaySocketServer {
2417
2454
  /**
2418
2455
  * If the client that disconnected (and is now in the reconnection-phase) was the room host,
2419
2456
  * pick a new room host immediately to avoid host-less phase (in case important logic is attached to the host)
2420
- * @param {string} roomId
2421
- * @param {string} clientId
2457
+ * @param {string} roomId - ID of the room that the disconnected client was in
2458
+ * @param {string} clientId - ID of the disconnected client
2422
2459
  */
2423
2460
  #changeHostIfDisconnected(roomId, clientId) {
2424
2461
  const room = this.#rooms[roomId];
@@ -2449,9 +2486,12 @@ class PlaySocketServer {
2449
2486
 
2450
2487
  /**
2451
2488
  * Check rate limit using token bucket algorithm
2489
+ * @param {string} connectionId - Random connection UUID which is different from the client ID
2490
+ * @param {string} actionType - A string describing the action
2491
+ * @returns {boolean} - Whether or not the action can be allowed, true means allowed, false means limited
2452
2492
  * @private
2453
2493
  */
2454
- #checkRateLimit(connectionId, operationType) {
2494
+ #checkRateLimit(connectionId, actionType) {
2455
2495
  const now = Date.now();
2456
2496
 
2457
2497
  if (!this.#rateLimits.has(connectionId)) {
@@ -2467,7 +2507,7 @@ class PlaySocketServer {
2467
2507
  limit.lastReset = now;
2468
2508
  }
2469
2509
 
2470
- const pointCost = operationType == "create_room" ? 5 : 1;
2510
+ const pointCost = actionType == "create_room" ? 5 : 1;
2471
2511
  if (limit.points < pointCost) return false;
2472
2512
 
2473
2513
  limit.points -= pointCost;
@@ -2476,6 +2516,7 @@ class PlaySocketServer {
2476
2516
 
2477
2517
  /**
2478
2518
  * Handle client disconnection
2519
+ * @param {WebSocket} ws - WebSocket client
2479
2520
  * @private
2480
2521
  */
2481
2522
  #handleDisconnection(ws) {
@@ -2504,7 +2545,7 @@ class PlaySocketServer {
2504
2545
  /**
2505
2546
  * Disconnect a client
2506
2547
  * @private
2507
- * @param {Object} ws
2548
+ * @param {WebSocket} ws - WebSocket client
2508
2549
  */
2509
2550
  #disconnectClient(ws) {
2510
2551
  this.#pendingDisconnects.delete(ws.clientId);
@@ -2545,8 +2586,10 @@ class PlaySocketServer {
2545
2586
  */
2546
2587
  onEvent(event, callback) {
2547
2588
  const validEvents = ["clientRegistered", "clientRegistrationRequested", "clientDisconnected", "clientJoinedRoom", "clientJoinRequested", "roomCreated", "roomCreationRequested", "requestReceived", "storageUpdated", "storageUpdateRequested", "roomDestroyed"];
2548
- if (!validEvents.includes(event)) return console.warn(`Invalid PlaySocket event type "${event}"`);
2549
- if (!this.#callbacks.has(event)) this.#callbacks.set(event, []);
2589
+ if (!validEvents.includes(event)) {
2590
+ console.warn(`Invalid PlaySocket event type "${event}"`);
2591
+ return;
2592
+ } if (!this.#callbacks.has(event)) this.#callbacks.set(event, []);
2550
2593
  this.#callbacks.get(event).push(callback);
2551
2594
  }
2552
2595
 
@@ -2566,6 +2609,9 @@ class PlaySocketServer {
2566
2609
 
2567
2610
  /**
2568
2611
  * Trigger an event to registered callbacks
2612
+ * @param {string} event - Event name
2613
+ * @param {...*} args - Arguments
2614
+ * @returns {any} - Undefined if no callbacks, true if all callbacks ran, what the first callback with a return statement returns if present
2569
2615
  * @private
2570
2616
  */
2571
2617
  async #triggerEvent(event, ...args) {
@@ -2585,7 +2631,8 @@ class PlaySocketServer {
2585
2631
 
2586
2632
  /**
2587
2633
  * Get snapshot of a room's storage
2588
- * @returns {Object} - Storage object
2634
+ * @param {string} roomId - ID of the room to get the storage from
2635
+ * @returns {object|undefined} - Storage object or undefined if the room doesn't exist
2589
2636
  */
2590
2637
  getRoomStorage(roomId) {
2591
2638
  const room = this.#rooms[roomId];
@@ -2596,7 +2643,7 @@ class PlaySocketServer {
2596
2643
  * Update a value in a room's storage
2597
2644
  * @param {string} roomId - Room ID
2598
2645
  * @param {string} key - Storage key
2599
- * @param {string} type - Operation type
2646
+ * @param {'set' | 'array-add' | 'array-add-unique' | 'array-remove-matching' | 'array-update-matching'} type - Operation type
2600
2647
  * @param {*} value - New value or value to operate on
2601
2648
  * @param {*} updateValue - New value for update-matching
2602
2649
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playsocketjs",
3
- "version": "2.5.1",
3
+ "version": "2.5.3",
4
4
  "description": "WebSocket wrapper for creating simple multiplayer systems with ease.",
5
5
  "type": "module",
6
6
  "module": "dist/playsocket-client.js",
@@ -9,18 +9,17 @@
9
9
  "import": "./dist/playsocket-client.js"
10
10
  },
11
11
  "./server": {
12
- "import": "./dist/playsocket-server.mjs",
13
- "require": "./dist/playsocket-server.cjs"
12
+ "import": "./dist/playsocket-server.js"
14
13
  }
15
14
  },
16
15
  "files": [
17
16
  "dist"
18
17
  ],
19
18
  "scripts": {
20
- "start": "node example/example-server.cjs",
21
- "start-module": "node example/example-server.mjs",
19
+ "start": "node example/example-server.js",
22
20
  "test": "echo \"Error: no test specified\" && exit 1",
23
- "build": "rollup -c rollup.config.mjs"
21
+ "build": "rollup -c rollup.config.js",
22
+ "lint": "eslint ./src"
24
23
  },
25
24
  "repository": {
26
25
  "type": "git",
@@ -28,11 +27,10 @@
28
27
  },
29
28
  "keywords": [
30
29
  "WebSocket",
31
- "data channel",
30
+ "Data channel",
32
31
  "Socket",
33
- "PlayPeerJS",
34
- "multiplayer",
35
- "game"
32
+ "Multiplayer",
33
+ "Game"
36
34
  ],
37
35
  "author": "PaulPlay",
38
36
  "license": "MIT",
@@ -41,9 +39,11 @@
41
39
  },
42
40
  "homepage": "https://github.com/therealPaulPlay/PlaySocketJS#readme",
43
41
  "devDependencies": {
44
- "@rollup/plugin-commonjs": "^28.0.2",
45
42
  "@rollup/plugin-node-resolve": "^16.0.0",
46
- "rollup": "^4.31.0"
43
+ "eslint": "^9.35.0",
44
+ "eslint-plugin-jsdoc": "^54.4.0",
45
+ "rollup": "^4.31.0",
46
+ "globals": "^16.3.0"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "ws": "^8.18.1"