@colyseus/sdk 0.17.13 → 0.17.15

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.
Files changed (72) hide show
  1. package/build/3rd_party/discord.cjs +1 -1
  2. package/build/3rd_party/discord.mjs +1 -1
  3. package/build/Auth.cjs +1 -1
  4. package/build/Auth.mjs +1 -1
  5. package/build/Client.cjs +3 -2
  6. package/build/Client.cjs.map +1 -1
  7. package/build/Client.d.ts +1 -1
  8. package/build/Client.mjs +3 -2
  9. package/build/Client.mjs.map +1 -1
  10. package/build/Connection.cjs +30 -1
  11. package/build/Connection.cjs.map +1 -1
  12. package/build/Connection.d.ts +1 -0
  13. package/build/Connection.mjs +27 -1
  14. package/build/Connection.mjs.map +1 -1
  15. package/build/HTTP.cjs +1 -1
  16. package/build/HTTP.mjs +1 -1
  17. package/build/Protocol.cjs +1 -1
  18. package/build/Protocol.mjs +1 -1
  19. package/build/Room.cjs +17 -14
  20. package/build/Room.cjs.map +1 -1
  21. package/build/Room.mjs +12 -9
  22. package/build/Room.mjs.map +1 -1
  23. package/build/Storage.cjs +1 -1
  24. package/build/Storage.mjs +1 -1
  25. package/build/core/nanoevents.cjs +1 -1
  26. package/build/core/nanoevents.mjs +1 -1
  27. package/build/core/signal.cjs +1 -1
  28. package/build/core/signal.mjs +1 -1
  29. package/build/core/utils.cjs +1 -1
  30. package/build/core/utils.mjs +1 -1
  31. package/build/debug.cjs +226 -113
  32. package/build/debug.cjs.map +1 -1
  33. package/build/debug.mjs +226 -113
  34. package/build/debug.mjs.map +1 -1
  35. package/build/errors/Errors.cjs +1 -12
  36. package/build/errors/Errors.cjs.map +1 -1
  37. package/build/errors/Errors.d.ts +0 -10
  38. package/build/errors/Errors.mjs +2 -13
  39. package/build/errors/Errors.mjs.map +1 -1
  40. package/build/index.cjs +11 -11
  41. package/build/index.cjs.map +1 -1
  42. package/build/index.d.ts +2 -2
  43. package/build/index.mjs +3 -3
  44. package/build/index.mjs.map +1 -1
  45. package/build/legacy.cjs +1 -1
  46. package/build/legacy.mjs +1 -1
  47. package/build/serializer/NoneSerializer.cjs +1 -1
  48. package/build/serializer/NoneSerializer.mjs +1 -1
  49. package/build/serializer/SchemaSerializer.cjs +1 -1
  50. package/build/serializer/SchemaSerializer.mjs +1 -1
  51. package/build/serializer/Serializer.cjs +1 -1
  52. package/build/serializer/Serializer.mjs +1 -1
  53. package/build/transport/H3Transport.cjs +1 -1
  54. package/build/transport/H3Transport.mjs +1 -1
  55. package/build/transport/WebSocketTransport.cjs +16 -5
  56. package/build/transport/WebSocketTransport.cjs.map +1 -1
  57. package/build/transport/WebSocketTransport.mjs +16 -5
  58. package/build/transport/WebSocketTransport.mjs.map +1 -1
  59. package/dist/colyseus-cocos-creator.js +118 -49
  60. package/dist/colyseus-cocos-creator.js.map +1 -1
  61. package/dist/colyseus.js +118 -49
  62. package/dist/colyseus.js.map +1 -1
  63. package/dist/debug.js +284 -143
  64. package/dist/debug.js.map +1 -1
  65. package/package.json +4 -4
  66. package/src/Client.ts +2 -2
  67. package/src/Connection.ts +30 -0
  68. package/src/Room.ts +13 -10
  69. package/src/debug.ts +246 -111
  70. package/src/errors/Errors.ts +0 -11
  71. package/src/index.ts +2 -2
  72. package/src/transport/WebSocketTransport.ts +16 -4
package/dist/debug.js CHANGED
@@ -3,8 +3,8 @@
3
3
  // This software is released under the MIT License.
4
4
  // https://opensource.org/license/MIT
5
5
  //
6
- // colyseus.js@0.17.13
7
- (function (schema, msgpackr, NodeWebSocket) {
6
+ // colyseus.js@0.17.15
7
+ (function (sharedTypes, schema, msgpackr, NodeWebSocket) {
8
8
  'use strict';
9
9
 
10
10
  /******************************************************************************
@@ -410,17 +410,6 @@
410
410
  __rewriteRelativeImportExtension: __rewriteRelativeImportExtension,
411
411
  };
412
412
 
413
- var CloseCode;
414
- (function (CloseCode) {
415
- CloseCode[CloseCode["NORMAL_CLOSURE"] = 1000] = "NORMAL_CLOSURE";
416
- CloseCode[CloseCode["GOING_AWAY"] = 1001] = "GOING_AWAY";
417
- CloseCode[CloseCode["NO_STATUS_RECEIVED"] = 1005] = "NO_STATUS_RECEIVED";
418
- CloseCode[CloseCode["ABNORMAL_CLOSURE"] = 1006] = "ABNORMAL_CLOSURE";
419
- CloseCode[CloseCode["CONSENTED"] = 4000] = "CONSENTED";
420
- CloseCode[CloseCode["SERVER_SHUTDOWN"] = 4001] = "SERVER_SHUTDOWN";
421
- CloseCode[CloseCode["WITH_ERROR"] = 4002] = "WITH_ERROR";
422
- CloseCode[CloseCode["DEVMODE_RESTART"] = 4010] = "DEVMODE_RESTART";
423
- })(CloseCode || (CloseCode = {}));
424
413
  class ServerError extends Error {
425
414
  constructor(code, message) {
426
415
  super(message);
@@ -618,12 +607,22 @@
618
607
  this.ws = new WebSocket(url, this.protocols);
619
608
  }
620
609
  this.ws.binaryType = 'arraybuffer';
621
- this.ws.onopen = this.events.onopen;
622
- this.ws.onmessage = this.events.onmessage;
623
- this.ws.onclose = this.events.onclose;
624
- this.ws.onerror = this.events.onerror;
610
+ this.ws.onopen = (event) => { var _a, _b; return (_b = (_a = this.events).onopen) === null || _b === void 0 ? void 0 : _b.call(_a, event); };
611
+ this.ws.onmessage = (event) => { var _a, _b; return (_b = (_a = this.events).onmessage) === null || _b === void 0 ? void 0 : _b.call(_a, event); };
612
+ this.ws.onclose = (event) => { var _a, _b; return (_b = (_a = this.events).onclose) === null || _b === void 0 ? void 0 : _b.call(_a, event); };
613
+ this.ws.onerror = (event) => { var _a, _b; return (_b = (_a = this.events).onerror) === null || _b === void 0 ? void 0 : _b.call(_a, event); };
625
614
  }
626
615
  close(code, reason) {
616
+ //
617
+ // trigger the onclose event immediately if the code is MAY_TRY_RECONNECT
618
+ // when "offline" event is triggered, the close frame is delayed. this
619
+ // way client can try to reconnect immediately.
620
+ //
621
+ if (code === sharedTypes.CloseCode.MAY_TRY_RECONNECT && this.events.onclose) {
622
+ this.ws.onclose = null;
623
+ this.events.onclose({ code, reason });
624
+ }
625
+ // then we close the connection
627
626
  this.ws.close(code, reason);
628
627
  }
629
628
  get isOpen() {
@@ -631,9 +630,23 @@
631
630
  }
632
631
  }
633
632
 
633
+ var _Connection__offlineListener;
634
+ const onOfflineListeners = [];
635
+ const hasGlobalEventListeners = typeof (addEventListener) === "function" && typeof (removeEventListener) === "function";
636
+ if (hasGlobalEventListeners) {
637
+ /**
638
+ * Detects when the network is offline and closes all connections.
639
+ * (When switching wifi networks, etc.)
640
+ */
641
+ addEventListener("offline", () => {
642
+ console.warn(`@colyseus/sdk: 🛑 Network offline. Closing ${onOfflineListeners.length} connection(s)`);
643
+ onOfflineListeners.forEach((listener) => listener());
644
+ }, false);
645
+ }
634
646
  class Connection {
635
647
  constructor(protocol) {
636
648
  this.events = {};
649
+ _Connection__offlineListener.set(this, (hasGlobalEventListeners) ? () => this.close(sharedTypes.CloseCode.MAY_TRY_RECONNECT) : null);
637
650
  switch (protocol) {
638
651
  case "h3":
639
652
  this.transport = new H3TransportTransport(this.events);
@@ -644,6 +657,18 @@
644
657
  }
645
658
  }
646
659
  connect(url, options) {
660
+ if (hasGlobalEventListeners) {
661
+ const onOpen = this.events.onopen;
662
+ this.events.onopen = (ev) => {
663
+ onOfflineListeners.push(__classPrivateFieldGet(this, _Connection__offlineListener, "f"));
664
+ onOpen === null || onOpen === void 0 ? void 0 : onOpen(ev);
665
+ };
666
+ const onClose = this.events.onclose;
667
+ this.events.onclose = (ev) => {
668
+ onOfflineListeners.splice(onOfflineListeners.indexOf(__classPrivateFieldGet(this, _Connection__offlineListener, "f")), 1);
669
+ onClose === null || onClose === void 0 ? void 0 : onClose(ev);
670
+ };
671
+ }
647
672
  this.url = url;
648
673
  this.options = options;
649
674
  this.transport.connect(url, options);
@@ -665,6 +690,7 @@
665
690
  return this.transport.isOpen;
666
691
  }
667
692
  }
693
+ _Connection__offlineListener = new WeakMap();
668
694
 
669
695
  // Use codes between 0~127 for lesser throughput (1 byte)
670
696
  var Protocol;
@@ -852,7 +878,7 @@
852
878
  // reconnection logic
853
879
  this.reconnection = {
854
880
  retryCount: 0,
855
- maxRetries: 8,
881
+ maxRetries: 15,
856
882
  delay: 100,
857
883
  minDelay: 100,
858
884
  maxDelay: 5000,
@@ -874,7 +900,6 @@
874
900
  this.serializer = new (getSerializer("schema"));
875
901
  this.serializer.state = new rootSchema();
876
902
  }
877
- this.onError((code, message) => { var _a; return (_a = console.warn) === null || _a === void 0 ? void 0 : _a.call(console, `colyseus.js - onError => (${code}) ${message}`); });
878
903
  this.onLeave(() => this.removeAllListeners());
879
904
  }
880
905
  connect(endpoint, options, headers) {
@@ -888,10 +913,10 @@
888
913
  this.onError.invoke(e.code, e.reason);
889
914
  return;
890
915
  }
891
- if (e.code === CloseCode.NO_STATUS_RECEIVED ||
892
- e.code === CloseCode.ABNORMAL_CLOSURE ||
893
- e.code === CloseCode.GOING_AWAY ||
894
- e.code === CloseCode.DEVMODE_RESTART) {
916
+ if (e.code === sharedTypes.CloseCode.NO_STATUS_RECEIVED ||
917
+ e.code === sharedTypes.CloseCode.ABNORMAL_CLOSURE ||
918
+ e.code === sharedTypes.CloseCode.GOING_AWAY ||
919
+ e.code === sharedTypes.CloseCode.MAY_TRY_RECONNECT) {
895
920
  this.onDrop.invoke(e.code, e.reason);
896
921
  this.handleReconnection();
897
922
  }
@@ -901,8 +926,6 @@
901
926
  }
902
927
  };
903
928
  this.connection.events.onerror = (e) => {
904
- var _a;
905
- (_a = console.warn) === null || _a === void 0 ? void 0 : _a.call(console, `Room, onError (${e.code}): ${e.reason}`);
906
929
  this.onError.invoke(e.code, e.reason);
907
930
  };
908
931
  /**
@@ -932,7 +955,7 @@
932
955
  }
933
956
  }
934
957
  else {
935
- this.onLeave.invoke(CloseCode.CONSENTED);
958
+ this.onLeave.invoke(sharedTypes.CloseCode.CONSENTED);
936
959
  }
937
960
  });
938
961
  }
@@ -940,6 +963,11 @@
940
963
  return this.onMessageHandlers.on(this.getMessageHandlerKey(type), callback);
941
964
  }
942
965
  ping(callback) {
966
+ var _a;
967
+ // skip if connection is not open
968
+ if (!((_a = this.connection) === null || _a === void 0 ? void 0 : _a.isOpen)) {
969
+ return;
970
+ }
943
971
  __classPrivateFieldSet(this, _Room_lastPingTime, now(), "f");
944
972
  __classPrivateFieldSet(this, _Room_pingCallback, callback, "f");
945
973
  this.packr.buffer[0] = Protocol.PING;
@@ -1097,7 +1125,7 @@
1097
1125
  this.dispatchMessage(type, buffer.subarray(it.offset));
1098
1126
  }
1099
1127
  else if (code === Protocol.PING) {
1100
- (_a = __classPrivateFieldGet(this, _Room_pingCallback, "f")) === null || _a === void 0 ? void 0 : _a.call(this, now() - __classPrivateFieldGet(this, _Room_lastPingTime, "f"));
1128
+ (_a = __classPrivateFieldGet(this, _Room_pingCallback, "f")) === null || _a === void 0 ? void 0 : _a.call(this, Math.round(now() - __classPrivateFieldGet(this, _Room_lastPingTime, "f")));
1101
1129
  __classPrivateFieldSet(this, _Room_pingCallback, undefined, "f");
1102
1130
  }
1103
1131
  }
@@ -1134,7 +1162,6 @@
1134
1162
  return;
1135
1163
  }
1136
1164
  if (!this.reconnection.isReconnecting) {
1137
- console.info(`[Colyseus reconnection]: ${String.fromCodePoint(0x1F504)} Re-establishing connection with roomId '${this.roomId}'...`); // 🔄
1138
1165
  this.reconnection.retryCount = 0;
1139
1166
  this.reconnection.isReconnecting = true;
1140
1167
  }
@@ -1143,16 +1170,18 @@
1143
1170
  retryReconnection() {
1144
1171
  this.reconnection.retryCount++;
1145
1172
  const delay = Math.min(this.reconnection.maxDelay, Math.max(this.reconnection.minDelay, this.reconnection.backoff(this.reconnection.retryCount, this.reconnection.delay)));
1146
- console.info(`[Colyseus reconnection]: ${String.fromCodePoint(0x1F504)} will retry in ${delay}ms... (${this.reconnection.retryCount} out of ${this.reconnection.maxRetries})`); // 🔄
1173
+ console.info(`[Colyseus reconnection]: ${String.fromCodePoint(0x023F3)} will retry in ${(delay / 1000).toFixed(1)} seconds...`); // 🔄
1147
1174
  // Wait before attempting reconnection
1148
1175
  setTimeout(() => {
1149
1176
  try {
1177
+ console.info(`[Colyseus reconnection]: ${String.fromCodePoint(0x1F504)} Re-establishing sessionId '${this.sessionId}' with roomId '${this.roomId}'... (attempt ${this.reconnection.retryCount} of ${this.reconnection.maxRetries})`); // 🔄
1150
1178
  this.connection.reconnect({
1151
1179
  reconnectionToken: this.reconnectionToken.split(":")[1],
1152
1180
  skipHandshake: true, // we already applied the handshake on first join
1153
1181
  });
1154
1182
  }
1155
1183
  catch (e) {
1184
+ console.log(".reconnect() failed", e);
1156
1185
  if (this.reconnection.retryCount < this.reconnection.maxRetries) {
1157
1186
  this.retryReconnection();
1158
1187
  }
@@ -1808,7 +1837,7 @@
1808
1837
  }
1809
1838
  };
1810
1839
  conn.events.onerror = (event) => {
1811
- reject(new ServerError(CloseCode.ABNORMAL_CLOSURE, `Failed to get latency: ${event.message}`));
1840
+ reject(new ServerError(sharedTypes.CloseCode.ABNORMAL_CLOSURE, `Failed to get latency: ${event.message}`));
1812
1841
  };
1813
1842
  conn.connect(this.getHttpEndpoint());
1814
1843
  });
@@ -1905,6 +1934,7 @@
1905
1934
  const settingsIcon = `<svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="200px" width="200px" xmlns="http://www.w3.org/2000/svg"><path d="M12.003 21c-.732 .001 -1.465 -.438 -1.678 -1.317a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c.886 .215 1.325 .957 1.318 1.694"></path><path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0"></path><path d="M19.001 19m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"></path><path d="M19.001 15.5v1.5"></path><path d="M19.001 21v1.5"></path><path d="M22.032 17.25l-1.299 .75"></path><path d="M17.27 20l-1.3 .75"></path><path d="M15.97 17.25l1.3 .75"></path><path d="M20.733 20l1.3 .75"></path></svg>`;
1906
1935
  const eyeSlashIcon = `<svg stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke-linecap="round" stroke-linejoin="round" height="16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg>`;
1907
1936
  const closeIcon = `<svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M400 145.49 366.51 112 256 222.51 145.49 112 112 145.49 222.51 256 112 366.51 145.49 400 256 289.49 366.51 400 400 366.51 289.49 256 400 145.49z"></path></svg>`;
1937
+ const disconnectIcon = `<svg fill="currentColor" viewBox="0 0 36 36" height="200px" width="200px"><path fill="currentColor" d="M18 24.42a4 4 0 1 0 4 4a4 4 0 0 0-4-4m0 6a2 2 0 1 1 2-2a2 2 0 0 1-2 2" class="clr-i-outline clr-i-outline-path-1"></path><path fill="currentColor" d="M26.21 21.85a1 1 0 0 0-.23-1.4a13.6 13.6 0 0 0-5-2.23l3.87 3.87a1 1 0 0 0 1.36-.24" class="clr-i-outline clr-i-outline-path-2"></path><path fill="currentColor" d="M18.05 10.72a21 21 0 0 0-4.16.43l1.74 1.74a19 19 0 0 1 2.42-.17A18.76 18.76 0 0 1 28.64 16a1 1 0 0 0 1.12-1.65a20.75 20.75 0 0 0-11.71-3.63" class="clr-i-outline clr-i-outline-path-3"></path><path fill="currentColor" d="M33.55 8.2A28.11 28.11 0 0 0 8.11 5.36l1.58 1.57a26 26 0 0 1 22.76 2.94a1 1 0 0 0 1.1-1.67" class="clr-i-outline clr-i-outline-path-4"></path><path fill="currentColor" d="m1.84 4.75l2.43 2.43c-.62.34-1.23.7-1.83 1.1a1 1 0 1 0 1.12 1.66C4.26 9.47 5 9 5.74 8.65l3.87 3.87a20.6 20.6 0 0 0-3.38 1.88A1 1 0 0 0 7.36 16a18.8 18.8 0 0 1 3.77-2l4.16 4.16A13.5 13.5 0 0 0 10 20.55a1 1 0 0 0 1.18 1.61A11.5 11.5 0 0 1 17 20l10.8 10.8l1.41-1.41l-26-26Z" class="clr-i-outline clr-i-outline-path-5"></path><path fill="none" d="M0 0h36v36H0z"></path></svg>`;
1908
1938
  // Store debug info per room
1909
1939
  const roomDebugInfo = new Map();
1910
1940
  // Single interval for all panels
@@ -3806,12 +3836,16 @@
3806
3836
  }
3807
3837
  // Helper function to format bytes
3808
3838
  function formatBytes(bytes) {
3809
- if (bytes === 0)
3839
+ if (!bytes) {
3810
3840
  return '0 B';
3841
+ }
3842
+ else if (bytes < 1) {
3843
+ bytes = 1; // avoid visual glitches
3844
+ }
3811
3845
  var k = 1024;
3812
3846
  var sizes = ['B', 'KB', 'MB', 'GB'];
3813
3847
  var i = Math.floor(Math.log(bytes) / Math.log(k));
3814
- return (bytes / Math.pow(k, i)).toFixed(1) + ' ' + sizes[i];
3848
+ return (Math.round(bytes) / Math.pow(k, i)).toFixed(1) + ' ' + sizes[i];
3815
3849
  }
3816
3850
  // Helper function to create debug panel for a room
3817
3851
  function createDebugPanel(uniquePanelId, debugInfo) {
@@ -3843,15 +3877,16 @@
3843
3877
  title.style.paddingBottom = '4px';
3844
3878
  title.style.display = 'flex';
3845
3879
  title.style.alignItems = 'center';
3846
- title.style.gap = '4px';
3880
+ title.style.justifyContent = 'space-between';
3881
+ title.style.gap = '8px';
3847
3882
  title.style.position = 'relative';
3848
- title.innerHTML = '<span style="display: inline-flex; align-items: center;"></span><span id="debug-title-text-' + uniquePanelId + '"></span><span id="debug-message-icon-' + uniquePanelId + '" style="display: none; align-items: center; margin-left: auto; cursor: pointer; opacity: 0.6; transition: opacity 0.2s; margin-right: 4px; width: 16px; height: 16px;">' + messageIcon.replace('height="200px" width="200px"', 'height="16" width="16"') + '</span><span id="debug-hamburger-icon-' + uniquePanelId + '" style="display: inline-flex; align-items: center; cursor: pointer; opacity: 0.6; transition: opacity 0.2s; margin-right: 4px; width: 16px; height: 16px;">' + treeViewIcon.replace('height="200px" width="200px"', 'height="16" width="16"') + '</span><span id="debug-info-icon-' + uniquePanelId + '" style="display: inline-flex; align-items: center; cursor: pointer; opacity: 0.6; transition: opacity 0.2s; width: 16px; height: 16px;">' + infoIcon + '</span>';
3849
- // Create tooltip for info icon
3883
+ title.innerHTML = '<span id="debug-title-text-' + uniquePanelId + '"><span class="debug-room-name"></span><span class="debug-info-icon" style="display: inline-flex; align-items: center; margin-left: 4px; cursor: pointer; opacity: 0.6; vertical-align: middle;">' + infoIcon.replace('height="200px" width="200px"', 'height="10" width="10"') + '</span></span><span id="debug-ping-' + uniquePanelId + '" style="font-size: 10px; font-weight: normal; color: #888;" title="Ping time">--</span>';
3884
+ // Create tooltip for info button (will be shown on hover)
3850
3885
  var tooltip = document.createElement('div');
3851
3886
  tooltip.id = 'debug-tooltip-' + uniquePanelId;
3852
3887
  tooltip.style.position = 'absolute';
3853
3888
  tooltip.style.top = '100%';
3854
- tooltip.style.right = '0';
3889
+ tooltip.style.left = '0';
3855
3890
  tooltip.style.marginTop = '4px';
3856
3891
  tooltip.style.padding = '6px 8px';
3857
3892
  tooltip.style.backgroundColor = 'rgba(0, 0, 0, 0.95)';
@@ -3863,60 +3898,149 @@
3863
3898
  tooltip.style.display = 'none';
3864
3899
  tooltip.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.5)';
3865
3900
  tooltip.style.lineHeight = '1.4';
3866
- tooltip.innerHTML = '<div><strong>Room ID:</strong> ' + debugInfo.roomId + '</div><div><strong>Session ID:</strong> N/A</div><div><strong>Host:</strong> N/A</div>';
3867
- title.appendChild(tooltip);
3868
- // Add hover handlers - use a small delay to ensure element exists
3869
- setTimeout(function () {
3870
- var infoIconElement = document.getElementById('debug-info-icon-' + uniquePanelId);
3871
- if (infoIconElement) {
3872
- var showTooltip = function () {
3873
- tooltip.style.display = 'block';
3874
- infoIconElement.style.opacity = '1';
3875
- };
3876
- var hideTooltip = function () {
3877
- tooltip.style.display = 'none';
3878
- infoIconElement.style.opacity = '0.6';
3879
- };
3880
- infoIconElement.addEventListener('mouseenter', showTooltip);
3881
- infoIconElement.addEventListener('mouseleave', hideTooltip);
3882
- // Also handle tooltip hover to keep it visible
3883
- tooltip.style.pointerEvents = 'auto';
3884
- tooltip.addEventListener('mouseenter', showTooltip);
3885
- tooltip.addEventListener('mouseleave', hideTooltip);
3886
- }
3887
- // Add click handler for hamburger icon
3888
- var hamburgerIconElement = document.getElementById('debug-hamburger-icon-' + uniquePanelId);
3889
- if (hamburgerIconElement) {
3890
- hamburgerIconElement.addEventListener('mouseenter', function () {
3891
- hamburgerIconElement.style.opacity = '1';
3892
- });
3893
- hamburgerIconElement.addEventListener('mouseleave', function () {
3894
- hamburgerIconElement.style.opacity = '0.6';
3895
- });
3896
- hamburgerIconElement.addEventListener('click', function (e) {
3897
- e.stopPropagation();
3898
- openStateInspectorModal(uniquePanelId);
3899
- });
3900
- }
3901
- // Add click handler for message icon
3902
- var messageIconElement = document.getElementById('debug-message-icon-' + uniquePanelId);
3903
- if (messageIconElement) {
3904
- messageIconElement.addEventListener('mouseenter', function () {
3905
- messageIconElement.style.opacity = '1';
3906
- });
3907
- messageIconElement.addEventListener('mouseleave', function () {
3908
- messageIconElement.style.opacity = '0.6';
3909
- });
3910
- messageIconElement.addEventListener('click', function (e) {
3911
- e.stopPropagation();
3912
- openSendMessagesModal(uniquePanelId);
3913
- });
3914
- }
3915
- }, 0);
3901
+ tooltip.innerHTML = '<div><strong>Room ID:</strong> ' + debugInfo.roomId + '</div><div><strong>Session ID:</strong> N/A</div>';
3916
3902
  var content = document.createElement('div');
3917
3903
  content.id = 'debug-content-' + uniquePanelId;
3904
+ // Create action buttons container at the bottom
3905
+ var actionsContainer = document.createElement('div');
3906
+ actionsContainer.id = 'debug-actions-' + uniquePanelId;
3907
+ actionsContainer.style.display = 'flex';
3908
+ actionsContainer.style.gap = '4px';
3909
+ actionsContainer.style.marginTop = '8px';
3910
+ actionsContainer.style.paddingTop = '6px';
3911
+ actionsContainer.style.borderTop = '1px solid rgba(255, 255, 255, 0.15)';
3912
+ actionsContainer.style.position = 'relative';
3913
+ // Helper function to create action button
3914
+ function createActionButton(id, icon, label, onClick) {
3915
+ var btn = document.createElement('button');
3916
+ btn.id = id;
3917
+ btn.style.display = 'flex';
3918
+ btn.style.alignItems = 'center';
3919
+ btn.style.gap = '4px';
3920
+ btn.style.padding = '4px 8px';
3921
+ btn.style.border = '1px solid rgba(255, 255, 255, 0.2)';
3922
+ btn.style.borderRadius = '4px';
3923
+ btn.style.background = 'rgba(255, 255, 255, 0.05)';
3924
+ btn.style.color = '#fff';
3925
+ btn.style.fontSize = '9px';
3926
+ btn.style.cursor = 'pointer';
3927
+ btn.style.transition = 'background 0.2s, border-color 0.2s';
3928
+ btn.innerHTML = '<span style="display: inline-flex; align-items: center; width: 12px; height: 12px;">' + icon + '</span><span>' + label + '</span>';
3929
+ btn.addEventListener('mouseenter', function () {
3930
+ btn.style.background = 'rgba(255, 255, 255, 0.15)';
3931
+ btn.style.borderColor = 'rgba(255, 255, 255, 0.3)';
3932
+ });
3933
+ btn.addEventListener('mouseleave', function () {
3934
+ btn.style.background = 'rgba(255, 255, 255, 0.05)';
3935
+ btn.style.borderColor = 'rgba(255, 255, 255, 0.2)';
3936
+ });
3937
+ btn.addEventListener('click', function (e) {
3938
+ e.stopPropagation();
3939
+ onClick();
3940
+ });
3941
+ return btn;
3942
+ }
3943
+ // Create action buttons
3944
+ var stateBtn = createActionButton('debug-state-btn-' + uniquePanelId, treeViewIcon.replace('height="200px" width="200px"', 'height="12" width="12"'), 'State', function () { openStateInspectorModal(uniquePanelId); });
3945
+ var messageBtn = createActionButton('debug-message-btn-' + uniquePanelId, messageIcon.replace('height="200px" width="200px"', 'height="12" width="12"'), 'Send', function () { openSendMessagesModal(uniquePanelId); });
3946
+ messageBtn.style.display = 'none'; // Hidden by default, shown when message types available
3947
+ // Create disconnect button (red, simulates abnormal websocket close)
3948
+ var disconnectBtn = createActionButton('debug-disconnect-btn-' + uniquePanelId, disconnectIcon.replace('height="200px" width="200px"', 'height="12" width="12"'), 'Drop', function () {
3949
+ var info = roomDebugInfo.get(uniquePanelId);
3950
+ if (info && info.room && info.room.connection) {
3951
+ // Simulate connection closure
3952
+ info.room.connection.close(sharedTypes.CloseCode.MAY_TRY_RECONNECT);
3953
+ }
3954
+ });
3955
+ // Track button state for hover effects
3956
+ var isReconnecting = false;
3957
+ // Helper to apply normal (red) button style
3958
+ function applyNormalStyle() {
3959
+ disconnectBtn.style.background = 'rgba(239, 68, 68, 0.2)';
3960
+ disconnectBtn.style.borderColor = 'rgba(239, 68, 68, 0.5)';
3961
+ disconnectBtn.style.color = '#ef4444';
3962
+ disconnectBtn.style.animation = '';
3963
+ disconnectBtn.style.pointerEvents = 'auto';
3964
+ disconnectBtn.style.opacity = '1';
3965
+ var labelSpan = disconnectBtn.querySelector('span:last-child');
3966
+ if (labelSpan)
3967
+ labelSpan.textContent = 'Drop';
3968
+ }
3969
+ // Helper to apply reconnecting (orange/pulsing) button style
3970
+ function applyReconnectingStyle() {
3971
+ disconnectBtn.style.background = 'rgba(251, 146, 60, 0.3)';
3972
+ disconnectBtn.style.borderColor = 'rgba(251, 146, 60, 0.6)';
3973
+ disconnectBtn.style.color = '#fb923c';
3974
+ disconnectBtn.style.animation = 'debug-pulse 1.5s ease-in-out infinite';
3975
+ disconnectBtn.style.pointerEvents = 'none';
3976
+ disconnectBtn.style.opacity = '0.8';
3977
+ var labelSpan = disconnectBtn.querySelector('span:last-child');
3978
+ if (labelSpan)
3979
+ labelSpan.textContent = 'Reconnecting...';
3980
+ }
3981
+ // Inject CSS animation if not already present
3982
+ if (!document.getElementById('debug-pulse-animation')) {
3983
+ var style = document.createElement('style');
3984
+ style.id = 'debug-pulse-animation';
3985
+ style.textContent = '@keyframes debug-pulse { 0%, 100% { opacity: 0.6; } 50% { opacity: 1; } }';
3986
+ document.head.appendChild(style);
3987
+ }
3988
+ // Apply initial style
3989
+ applyNormalStyle();
3990
+ // Register onDrop callback to show reconnecting state
3991
+ if (debugInfo.room) {
3992
+ debugInfo.room.onDrop(function () {
3993
+ isReconnecting = true;
3994
+ applyReconnectingStyle();
3995
+ });
3996
+ // Register onReconnect callback to restore normal state
3997
+ debugInfo.room.onReconnect(function () {
3998
+ isReconnecting = false;
3999
+ applyNormalStyle();
4000
+ });
4001
+ }
4002
+ // Hover effects (only when not reconnecting)
4003
+ disconnectBtn.addEventListener('mouseenter', function () {
4004
+ if (!isReconnecting) {
4005
+ disconnectBtn.style.background = 'rgba(239, 68, 68, 0.35)';
4006
+ disconnectBtn.style.borderColor = 'rgba(239, 68, 68, 0.7)';
4007
+ }
4008
+ });
4009
+ disconnectBtn.addEventListener('mouseleave', function () {
4010
+ if (!isReconnecting) {
4011
+ disconnectBtn.style.background = 'rgba(239, 68, 68, 0.2)';
4012
+ disconnectBtn.style.borderColor = 'rgba(239, 68, 68, 0.5)';
4013
+ }
4014
+ });
4015
+ // Add tooltip hover handlers to info icon in title
4016
+ title.appendChild(tooltip);
4017
+ var infoIconEl = title.querySelector('.debug-info-icon');
4018
+ var tooltipTimeout = null;
4019
+ var showTooltip = function () {
4020
+ if (tooltipTimeout) {
4021
+ clearTimeout(tooltipTimeout);
4022
+ tooltipTimeout = null;
4023
+ }
4024
+ tooltip.style.display = 'block';
4025
+ };
4026
+ var hideTooltip = function () {
4027
+ tooltipTimeout = setTimeout(function () {
4028
+ tooltip.style.display = 'none';
4029
+ }, 100);
4030
+ };
4031
+ if (infoIconEl) {
4032
+ infoIconEl.addEventListener('mouseenter', showTooltip);
4033
+ infoIconEl.addEventListener('mouseleave', hideTooltip);
4034
+ }
4035
+ tooltip.style.pointerEvents = 'auto';
4036
+ tooltip.addEventListener('mouseenter', showTooltip);
4037
+ tooltip.addEventListener('mouseleave', hideTooltip);
4038
+ actionsContainer.appendChild(stateBtn);
4039
+ actionsContainer.appendChild(messageBtn);
4040
+ actionsContainer.appendChild(disconnectBtn);
3918
4041
  panel.appendChild(title);
3919
4042
  panel.appendChild(content);
4043
+ panel.appendChild(actionsContainer);
3920
4044
  // Prepend panel to body so new panels appear first
3921
4045
  if (document.body.firstChild) {
3922
4046
  document.body.insertBefore(panel, document.body.firstChild);
@@ -3991,16 +4115,27 @@
3991
4115
  title = document.getElementById(titleId);
3992
4116
  }
3993
4117
  }
3994
- // Update title with room name only (roomId, sessionId, and Host are in tooltip)
3995
- document.getElementById('debug-title-text-' + uniquePanelId).textContent = debugInfo.roomName;
3996
- document.getElementById('debug-tooltip-' + uniquePanelId).innerHTML = '<div><strong>Room ID:</strong> ' + debugInfo.roomId + '</div><div><strong>Session ID:</strong> ' + debugInfo.sessionId + '</div><div><strong>Host:</strong> ' + debugInfo.host + '</div>';
4118
+ // Update title with room name only (roomId and sessionId are in tooltip)
4119
+ var titleTextEl = document.getElementById('debug-title-text-' + uniquePanelId);
4120
+ var roomNameEl = titleTextEl === null || titleTextEl === void 0 ? void 0 : titleTextEl.querySelector('.debug-room-name');
4121
+ if (roomNameEl)
4122
+ roomNameEl.textContent = debugInfo.roomName;
4123
+ document.getElementById('debug-tooltip-' + uniquePanelId).innerHTML = '<div><strong>Room ID:</strong> ' + debugInfo.roomId + '</div><div><strong>Session ID:</strong> ' + debugInfo.sessionId + '</div>';
4124
+ // Update ping in header
4125
+ var pingDisplay = debugInfo.pingMs !== null ? debugInfo.pingMs + 'ms' : '--';
4126
+ var pingColor = debugInfo.pingMs !== null ? (debugInfo.pingMs < 100 ? '#22c55e' : debugInfo.pingMs < 200 ? '#eab308' : '#ef4444') : '#888';
4127
+ var pingElement = document.getElementById('debug-ping-' + uniquePanelId);
4128
+ if (pingElement) {
4129
+ pingElement.textContent = pingDisplay;
4130
+ pingElement.style.color = pingColor;
4131
+ }
3997
4132
  var html = '<div style="line-height: 1.3;">';
3998
4133
  html += '<div style="font-size: 10px; display: flex; gap: 8px;">';
3999
4134
  html += '<div style="flex: 1;">';
4000
4135
  html += '<div style="margin-bottom: 4px;"><div style="display: flex; align-items: center; gap: 6px;"><span style="display: inline-flex; align-items: center; width: 18px; height: 18px; color: #FF9800;">' + envelopeUp + '</span><span style="color: #FF9800;">' + formatBytes(debugInfo.bytesSentPerSec) + '/s</span></div><div style="margin-left: 24px; opacity: 0.7; font-size: 9px;">' + debugInfo.messagesSentPerSec.toFixed(0) + ' messages</div></div>';
4001
4136
  html += '<div><div style="display: flex; align-items: center; gap: 6px;"><span style="display: inline-flex; align-items: center; width: 18px; height: 18px; color: #2196F3;">' + envelopeDown + '</span><span style="color: #2196F3;">' + formatBytes(debugInfo.bytesReceivedPerSec) + '/s</span></div><div style="margin-left: 24px; opacity: 0.7; font-size: 9px;">' + debugInfo.messagesReceivedPerSec.toFixed(0) + ' messages</div></div>';
4002
4137
  html += '</div>';
4003
- html += '<div style="display: flex; flex-direction: column; gap: 4px;">';
4138
+ html += '<div style="display: flex; flex-direction: column; gap: 4px; align-items: flex-end;">';
4004
4139
  html += '<canvas id="graph-sent-' + uniquePanelId + '" width="80" height="30" style="display: block;"></canvas>';
4005
4140
  html += '<canvas id="graph-received-' + uniquePanelId + '" width="80" height="30" style="display: block;"></canvas>';
4006
4141
  html += '</div>';
@@ -4157,16 +4292,28 @@
4157
4292
  bytesReceivedHistory: [],
4158
4293
  // historyTimestamps: [],
4159
4294
  maxHistoryLength: 60, // Keep last 60 data points (1 minute at 1 second intervals)
4160
- messageTypes: null // Will store message types from __playground_message_types
4295
+ messageTypes: null, // Will store message types from __playground_message_types
4296
+ pingMs: null, // Current ping value in milliseconds
4297
+ pingInterval: null // Interval for pinging the room
4161
4298
  };
4162
4299
  roomDebugInfo.set(uniquePanelId, debugInfo);
4300
+ // Start ping interval (every 2 seconds)
4301
+ debugInfo.pingInterval = setInterval(() => {
4302
+ room.ping((ms) => {
4303
+ debugInfo.pingMs = ms;
4304
+ });
4305
+ }, 2000);
4306
+ // Initial ping
4307
+ room.ping((ms) => {
4308
+ debugInfo.pingMs = ms;
4309
+ });
4163
4310
  // Listen for __playground_message_types message
4164
4311
  room.onMessage('__playground_message_types', (messageTypes) => {
4165
4312
  debugInfo.messageTypes = messageTypes;
4166
- // Show/hide message icon based on message types availability
4167
- var messageIconElement = document.getElementById('debug-message-icon-' + uniquePanelId);
4168
- if (messageIconElement) {
4169
- messageIconElement.style.display = messageTypes ? 'inline-flex' : 'none';
4313
+ // Show/hide message button based on message types availability
4314
+ var messageBtnElement = document.getElementById('debug-message-btn-' + uniquePanelId);
4315
+ if (messageBtnElement) {
4316
+ messageBtnElement.style.display = messageTypes ? 'flex' : 'none';
4170
4317
  }
4171
4318
  });
4172
4319
  // Helper function to track received message/bytes
@@ -4214,41 +4361,38 @@
4214
4361
  debugInfo.bytesSent += data.length;
4215
4362
  debugInfo.bytesSentDelta += data.length;
4216
4363
  }
4217
- // Monkey-patch: WebSocket transport
4218
- if (transport.ws) {
4219
- const originalOnMessage = transport.ws.onmessage;
4220
- const ws = transport.ws;
4221
- transport.ws.onmessage = function (event) {
4222
- // Clone event data to avoid issues with delayed processing
4223
- var eventData = event.data;
4224
- if (eventData instanceof Blob) {
4225
- eventData = eventData.slice();
4226
- }
4227
- else if (eventData instanceof ArrayBuffer) {
4228
- eventData = eventData.slice(0);
4229
- }
4230
- else if (typeof eventData === 'string') {
4231
- eventData = eventData;
4232
- }
4233
- trackReceivedMessage(eventData);
4234
- // Apply latency simulation for received messages
4235
- if (preferences.latencySimulation.enabled && preferences.latencySimulation.delay > 0) {
4236
- setTimeout(function () {
4237
- // Create a synthetic event-like object
4238
- var syntheticEvent = {
4239
- data: eventData,
4240
- target: ws,
4241
- currentTarget: ws,
4242
- type: 'message'
4243
- };
4244
- originalOnMessage.call(ws, syntheticEvent);
4245
- }, preferences.latencySimulation.delay);
4246
- }
4247
- else {
4248
- return originalOnMessage.apply(this, arguments);
4249
- }
4250
- };
4251
- }
4364
+ // Monkey-patch: track received messages through onmessage event
4365
+ const originalOnMessage = transport.events.onmessage;
4366
+ transport.events.onmessage = function (event) {
4367
+ // Clone event data to avoid issues with delayed processing
4368
+ var eventData = event.data;
4369
+ if (eventData instanceof Blob) {
4370
+ eventData = eventData.slice();
4371
+ }
4372
+ else if (eventData instanceof ArrayBuffer) {
4373
+ eventData = eventData.slice(0);
4374
+ }
4375
+ else if (typeof eventData === 'string') {
4376
+ eventData = eventData;
4377
+ }
4378
+ trackReceivedMessage(eventData);
4379
+ // Apply latency simulation for received messages
4380
+ if (preferences.latencySimulation.enabled && preferences.latencySimulation.delay > 0) {
4381
+ setTimeout(function () {
4382
+ // Create a synthetic event-like object
4383
+ var syntheticEvent = {
4384
+ data: eventData,
4385
+ target: event.target,
4386
+ currentTarget: event.currentTarget,
4387
+ type: 'message'
4388
+ };
4389
+ originalOnMessage.call(event.target, syntheticEvent);
4390
+ }, preferences.latencySimulation.delay);
4391
+ }
4392
+ else {
4393
+ return originalOnMessage.apply(this, arguments);
4394
+ }
4395
+ };
4252
4396
  // Monkey-patch: sending messages through room connection
4253
4397
  const originalSend = room.connection.send.bind(room.connection);
4254
4398
  room.connection.send = function (data) {
@@ -4278,6 +4422,11 @@
4278
4422
  ensureGlobalUpdateInterval();
4279
4423
  // Clean up on room leave
4280
4424
  room.onLeave.once(() => {
4425
+ // Clear ping interval
4426
+ if (debugInfo.pingInterval !== null) {
4427
+ clearInterval(debugInfo.pingInterval);
4428
+ debugInfo.pingInterval = null;
4429
+ }
4281
4430
  roomDebugInfo.delete(uniquePanelId);
4282
4431
  var panel = document.getElementById('debug-panel-' + uniquePanelId);
4283
4432
  if (panel) {
@@ -4300,31 +4449,23 @@
4300
4449
  // Patch joinOrCreate
4301
4450
  Client.prototype.joinOrCreate = function () {
4302
4451
  var promise = originalJoinOrCreate.apply(this, arguments);
4303
- return promise.then(function (room) {
4304
- return patchRoom(room);
4305
- });
4452
+ return promise.then((room) => patchRoom(room));
4306
4453
  };
4307
4454
  // Patch join
4308
4455
  Client.prototype.join = function () {
4309
4456
  var promise = originalJoin.apply(this, arguments);
4310
- return promise.then(function (room) {
4311
- return patchRoom(room);
4312
- });
4457
+ return promise.then((room) => patchRoom(room));
4313
4458
  };
4314
4459
  // Patch create
4315
4460
  Client.prototype.create = function () {
4316
4461
  var promise = originalCreate.apply(this, arguments);
4317
- return promise.then(function (room) {
4318
- return patchRoom(room);
4319
- });
4462
+ return promise.then((room) => patchRoom(room));
4320
4463
  };
4321
4464
  // Patch reconnect
4322
4465
  if (originalReconnect) {
4323
4466
  Client.prototype.reconnect = function () {
4324
4467
  var promise = originalReconnect.apply(this, arguments);
4325
- return promise.then(function (room) {
4326
- return patchRoom(room);
4327
- });
4468
+ return promise.then((room) => patchRoom(room));
4328
4469
  };
4329
4470
  }
4330
4471
  }
@@ -4339,5 +4480,5 @@
4339
4480
  initialize();
4340
4481
  }
4341
4482
 
4342
- })(Colyseus, Colyseus, Colyseus);
4483
+ })(Colyseus, Colyseus, Colyseus, Colyseus);
4343
4484
  //# sourceMappingURL=debug.js.map