@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/build/debug.mjs CHANGED
@@ -3,8 +3,9 @@
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
6
+ // colyseus.js@0.17.15
7
7
  import { Client } from './Client.mjs';
8
+ import { CloseCode } from '@colyseus/shared-types';
8
9
 
9
10
  const logoIcon = `<svg viewBox="0 0 488.94 541.2" style="width: 100%; height: 100%;">
10
11
  <g>
@@ -23,6 +24,7 @@ const infoIcon = `<svg stroke="currentColor" fill="currentColor" stroke-width="0
23
24
  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>`;
24
25
  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>`;
25
26
  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>`;
27
+ 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>`;
26
28
  // Store debug info per room
27
29
  const roomDebugInfo = new Map();
28
30
  // Single interval for all panels
@@ -1918,12 +1920,16 @@ function hidePanelsForSession() {
1918
1920
  }
1919
1921
  // Helper function to format bytes
1920
1922
  function formatBytes(bytes) {
1921
- if (bytes === 0)
1923
+ if (!bytes) {
1922
1924
  return '0 B';
1925
+ }
1926
+ else if (bytes < 1) {
1927
+ bytes = 1; // avoid visual glitches
1928
+ }
1923
1929
  var k = 1024;
1924
1930
  var sizes = ['B', 'KB', 'MB', 'GB'];
1925
1931
  var i = Math.floor(Math.log(bytes) / Math.log(k));
1926
- return (bytes / Math.pow(k, i)).toFixed(1) + ' ' + sizes[i];
1932
+ return (Math.round(bytes) / Math.pow(k, i)).toFixed(1) + ' ' + sizes[i];
1927
1933
  }
1928
1934
  // Helper function to create debug panel for a room
1929
1935
  function createDebugPanel(uniquePanelId, debugInfo) {
@@ -1955,15 +1961,16 @@ function createDebugPanel(uniquePanelId, debugInfo) {
1955
1961
  title.style.paddingBottom = '4px';
1956
1962
  title.style.display = 'flex';
1957
1963
  title.style.alignItems = 'center';
1958
- title.style.gap = '4px';
1964
+ title.style.justifyContent = 'space-between';
1965
+ title.style.gap = '8px';
1959
1966
  title.style.position = 'relative';
1960
- 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>';
1961
- // Create tooltip for info icon
1967
+ 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>';
1968
+ // Create tooltip for info button (will be shown on hover)
1962
1969
  var tooltip = document.createElement('div');
1963
1970
  tooltip.id = 'debug-tooltip-' + uniquePanelId;
1964
1971
  tooltip.style.position = 'absolute';
1965
1972
  tooltip.style.top = '100%';
1966
- tooltip.style.right = '0';
1973
+ tooltip.style.left = '0';
1967
1974
  tooltip.style.marginTop = '4px';
1968
1975
  tooltip.style.padding = '6px 8px';
1969
1976
  tooltip.style.backgroundColor = 'rgba(0, 0, 0, 0.95)';
@@ -1975,60 +1982,149 @@ function createDebugPanel(uniquePanelId, debugInfo) {
1975
1982
  tooltip.style.display = 'none';
1976
1983
  tooltip.style.boxShadow = '0 2px 8px rgba(0, 0, 0, 0.5)';
1977
1984
  tooltip.style.lineHeight = '1.4';
1978
- 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>';
1979
- title.appendChild(tooltip);
1980
- // Add hover handlers - use a small delay to ensure element exists
1981
- setTimeout(function () {
1982
- var infoIconElement = document.getElementById('debug-info-icon-' + uniquePanelId);
1983
- if (infoIconElement) {
1984
- var showTooltip = function () {
1985
- tooltip.style.display = 'block';
1986
- infoIconElement.style.opacity = '1';
1987
- };
1988
- var hideTooltip = function () {
1989
- tooltip.style.display = 'none';
1990
- infoIconElement.style.opacity = '0.6';
1991
- };
1992
- infoIconElement.addEventListener('mouseenter', showTooltip);
1993
- infoIconElement.addEventListener('mouseleave', hideTooltip);
1994
- // Also handle tooltip hover to keep it visible
1995
- tooltip.style.pointerEvents = 'auto';
1996
- tooltip.addEventListener('mouseenter', showTooltip);
1997
- tooltip.addEventListener('mouseleave', hideTooltip);
1998
- }
1999
- // Add click handler for hamburger icon
2000
- var hamburgerIconElement = document.getElementById('debug-hamburger-icon-' + uniquePanelId);
2001
- if (hamburgerIconElement) {
2002
- hamburgerIconElement.addEventListener('mouseenter', function () {
2003
- hamburgerIconElement.style.opacity = '1';
2004
- });
2005
- hamburgerIconElement.addEventListener('mouseleave', function () {
2006
- hamburgerIconElement.style.opacity = '0.6';
2007
- });
2008
- hamburgerIconElement.addEventListener('click', function (e) {
2009
- e.stopPropagation();
2010
- openStateInspectorModal(uniquePanelId);
2011
- });
2012
- }
2013
- // Add click handler for message icon
2014
- var messageIconElement = document.getElementById('debug-message-icon-' + uniquePanelId);
2015
- if (messageIconElement) {
2016
- messageIconElement.addEventListener('mouseenter', function () {
2017
- messageIconElement.style.opacity = '1';
2018
- });
2019
- messageIconElement.addEventListener('mouseleave', function () {
2020
- messageIconElement.style.opacity = '0.6';
2021
- });
2022
- messageIconElement.addEventListener('click', function (e) {
2023
- e.stopPropagation();
2024
- openSendMessagesModal(uniquePanelId);
2025
- });
2026
- }
2027
- }, 0);
1985
+ tooltip.innerHTML = '<div><strong>Room ID:</strong> ' + debugInfo.roomId + '</div><div><strong>Session ID:</strong> N/A</div>';
2028
1986
  var content = document.createElement('div');
2029
1987
  content.id = 'debug-content-' + uniquePanelId;
1988
+ // Create action buttons container at the bottom
1989
+ var actionsContainer = document.createElement('div');
1990
+ actionsContainer.id = 'debug-actions-' + uniquePanelId;
1991
+ actionsContainer.style.display = 'flex';
1992
+ actionsContainer.style.gap = '4px';
1993
+ actionsContainer.style.marginTop = '8px';
1994
+ actionsContainer.style.paddingTop = '6px';
1995
+ actionsContainer.style.borderTop = '1px solid rgba(255, 255, 255, 0.15)';
1996
+ actionsContainer.style.position = 'relative';
1997
+ // Helper function to create action button
1998
+ function createActionButton(id, icon, label, onClick) {
1999
+ var btn = document.createElement('button');
2000
+ btn.id = id;
2001
+ btn.style.display = 'flex';
2002
+ btn.style.alignItems = 'center';
2003
+ btn.style.gap = '4px';
2004
+ btn.style.padding = '4px 8px';
2005
+ btn.style.border = '1px solid rgba(255, 255, 255, 0.2)';
2006
+ btn.style.borderRadius = '4px';
2007
+ btn.style.background = 'rgba(255, 255, 255, 0.05)';
2008
+ btn.style.color = '#fff';
2009
+ btn.style.fontSize = '9px';
2010
+ btn.style.cursor = 'pointer';
2011
+ btn.style.transition = 'background 0.2s, border-color 0.2s';
2012
+ btn.innerHTML = '<span style="display: inline-flex; align-items: center; width: 12px; height: 12px;">' + icon + '</span><span>' + label + '</span>';
2013
+ btn.addEventListener('mouseenter', function () {
2014
+ btn.style.background = 'rgba(255, 255, 255, 0.15)';
2015
+ btn.style.borderColor = 'rgba(255, 255, 255, 0.3)';
2016
+ });
2017
+ btn.addEventListener('mouseleave', function () {
2018
+ btn.style.background = 'rgba(255, 255, 255, 0.05)';
2019
+ btn.style.borderColor = 'rgba(255, 255, 255, 0.2)';
2020
+ });
2021
+ btn.addEventListener('click', function (e) {
2022
+ e.stopPropagation();
2023
+ onClick();
2024
+ });
2025
+ return btn;
2026
+ }
2027
+ // Create action buttons
2028
+ var stateBtn = createActionButton('debug-state-btn-' + uniquePanelId, treeViewIcon.replace('height="200px" width="200px"', 'height="12" width="12"'), 'State', function () { openStateInspectorModal(uniquePanelId); });
2029
+ var messageBtn = createActionButton('debug-message-btn-' + uniquePanelId, messageIcon.replace('height="200px" width="200px"', 'height="12" width="12"'), 'Send', function () { openSendMessagesModal(uniquePanelId); });
2030
+ messageBtn.style.display = 'none'; // Hidden by default, shown when message types available
2031
+ // Create disconnect button (red, simulates abnormal websocket close)
2032
+ var disconnectBtn = createActionButton('debug-disconnect-btn-' + uniquePanelId, disconnectIcon.replace('height="200px" width="200px"', 'height="12" width="12"'), 'Drop', function () {
2033
+ var info = roomDebugInfo.get(uniquePanelId);
2034
+ if (info && info.room && info.room.connection) {
2035
+ // Simulate connection closure
2036
+ info.room.connection.close(CloseCode.MAY_TRY_RECONNECT);
2037
+ }
2038
+ });
2039
+ // Track button state for hover effects
2040
+ var isReconnecting = false;
2041
+ // Helper to apply normal (red) button style
2042
+ function applyNormalStyle() {
2043
+ disconnectBtn.style.background = 'rgba(239, 68, 68, 0.2)';
2044
+ disconnectBtn.style.borderColor = 'rgba(239, 68, 68, 0.5)';
2045
+ disconnectBtn.style.color = '#ef4444';
2046
+ disconnectBtn.style.animation = '';
2047
+ disconnectBtn.style.pointerEvents = 'auto';
2048
+ disconnectBtn.style.opacity = '1';
2049
+ var labelSpan = disconnectBtn.querySelector('span:last-child');
2050
+ if (labelSpan)
2051
+ labelSpan.textContent = 'Drop';
2052
+ }
2053
+ // Helper to apply reconnecting (orange/pulsing) button style
2054
+ function applyReconnectingStyle() {
2055
+ disconnectBtn.style.background = 'rgba(251, 146, 60, 0.3)';
2056
+ disconnectBtn.style.borderColor = 'rgba(251, 146, 60, 0.6)';
2057
+ disconnectBtn.style.color = '#fb923c';
2058
+ disconnectBtn.style.animation = 'debug-pulse 1.5s ease-in-out infinite';
2059
+ disconnectBtn.style.pointerEvents = 'none';
2060
+ disconnectBtn.style.opacity = '0.8';
2061
+ var labelSpan = disconnectBtn.querySelector('span:last-child');
2062
+ if (labelSpan)
2063
+ labelSpan.textContent = 'Reconnecting...';
2064
+ }
2065
+ // Inject CSS animation if not already present
2066
+ if (!document.getElementById('debug-pulse-animation')) {
2067
+ var style = document.createElement('style');
2068
+ style.id = 'debug-pulse-animation';
2069
+ style.textContent = '@keyframes debug-pulse { 0%, 100% { opacity: 0.6; } 50% { opacity: 1; } }';
2070
+ document.head.appendChild(style);
2071
+ }
2072
+ // Apply initial style
2073
+ applyNormalStyle();
2074
+ // Register onDrop callback to show reconnecting state
2075
+ if (debugInfo.room) {
2076
+ debugInfo.room.onDrop(function () {
2077
+ isReconnecting = true;
2078
+ applyReconnectingStyle();
2079
+ });
2080
+ // Register onReconnect callback to restore normal state
2081
+ debugInfo.room.onReconnect(function () {
2082
+ isReconnecting = false;
2083
+ applyNormalStyle();
2084
+ });
2085
+ }
2086
+ // Hover effects (only when not reconnecting)
2087
+ disconnectBtn.addEventListener('mouseenter', function () {
2088
+ if (!isReconnecting) {
2089
+ disconnectBtn.style.background = 'rgba(239, 68, 68, 0.35)';
2090
+ disconnectBtn.style.borderColor = 'rgba(239, 68, 68, 0.7)';
2091
+ }
2092
+ });
2093
+ disconnectBtn.addEventListener('mouseleave', function () {
2094
+ if (!isReconnecting) {
2095
+ disconnectBtn.style.background = 'rgba(239, 68, 68, 0.2)';
2096
+ disconnectBtn.style.borderColor = 'rgba(239, 68, 68, 0.5)';
2097
+ }
2098
+ });
2099
+ // Add tooltip hover handlers to info icon in title
2100
+ title.appendChild(tooltip);
2101
+ var infoIconEl = title.querySelector('.debug-info-icon');
2102
+ var tooltipTimeout = null;
2103
+ var showTooltip = function () {
2104
+ if (tooltipTimeout) {
2105
+ clearTimeout(tooltipTimeout);
2106
+ tooltipTimeout = null;
2107
+ }
2108
+ tooltip.style.display = 'block';
2109
+ };
2110
+ var hideTooltip = function () {
2111
+ tooltipTimeout = setTimeout(function () {
2112
+ tooltip.style.display = 'none';
2113
+ }, 100);
2114
+ };
2115
+ if (infoIconEl) {
2116
+ infoIconEl.addEventListener('mouseenter', showTooltip);
2117
+ infoIconEl.addEventListener('mouseleave', hideTooltip);
2118
+ }
2119
+ tooltip.style.pointerEvents = 'auto';
2120
+ tooltip.addEventListener('mouseenter', showTooltip);
2121
+ tooltip.addEventListener('mouseleave', hideTooltip);
2122
+ actionsContainer.appendChild(stateBtn);
2123
+ actionsContainer.appendChild(messageBtn);
2124
+ actionsContainer.appendChild(disconnectBtn);
2030
2125
  panel.appendChild(title);
2031
2126
  panel.appendChild(content);
2127
+ panel.appendChild(actionsContainer);
2032
2128
  // Prepend panel to body so new panels appear first
2033
2129
  if (document.body.firstChild) {
2034
2130
  document.body.insertBefore(panel, document.body.firstChild);
@@ -2103,16 +2199,27 @@ function updateDebugPanel(uniquePanelId, debugInfo) {
2103
2199
  title = document.getElementById(titleId);
2104
2200
  }
2105
2201
  }
2106
- // Update title with room name only (roomId, sessionId, and Host are in tooltip)
2107
- document.getElementById('debug-title-text-' + uniquePanelId).textContent = debugInfo.roomName;
2108
- 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>';
2202
+ // Update title with room name only (roomId and sessionId are in tooltip)
2203
+ var titleTextEl = document.getElementById('debug-title-text-' + uniquePanelId);
2204
+ var roomNameEl = titleTextEl?.querySelector('.debug-room-name');
2205
+ if (roomNameEl)
2206
+ roomNameEl.textContent = debugInfo.roomName;
2207
+ document.getElementById('debug-tooltip-' + uniquePanelId).innerHTML = '<div><strong>Room ID:</strong> ' + debugInfo.roomId + '</div><div><strong>Session ID:</strong> ' + debugInfo.sessionId + '</div>';
2208
+ // Update ping in header
2209
+ var pingDisplay = debugInfo.pingMs !== null ? debugInfo.pingMs + 'ms' : '--';
2210
+ var pingColor = debugInfo.pingMs !== null ? (debugInfo.pingMs < 100 ? '#22c55e' : debugInfo.pingMs < 200 ? '#eab308' : '#ef4444') : '#888';
2211
+ var pingElement = document.getElementById('debug-ping-' + uniquePanelId);
2212
+ if (pingElement) {
2213
+ pingElement.textContent = pingDisplay;
2214
+ pingElement.style.color = pingColor;
2215
+ }
2109
2216
  var html = '<div style="line-height: 1.3;">';
2110
2217
  html += '<div style="font-size: 10px; display: flex; gap: 8px;">';
2111
2218
  html += '<div style="flex: 1;">';
2112
2219
  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>';
2113
2220
  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>';
2114
2221
  html += '</div>';
2115
- html += '<div style="display: flex; flex-direction: column; gap: 4px;">';
2222
+ html += '<div style="display: flex; flex-direction: column; gap: 4px; align-items: flex-end;">';
2116
2223
  html += '<canvas id="graph-sent-' + uniquePanelId + '" width="80" height="30" style="display: block;"></canvas>';
2117
2224
  html += '<canvas id="graph-received-' + uniquePanelId + '" width="80" height="30" style="display: block;"></canvas>';
2118
2225
  html += '</div>';
@@ -2268,16 +2375,28 @@ function applyMonkeyPatches() {
2268
2375
  bytesReceivedHistory: [],
2269
2376
  // historyTimestamps: [],
2270
2377
  maxHistoryLength: 60, // Keep last 60 data points (1 minute at 1 second intervals)
2271
- messageTypes: null // Will store message types from __playground_message_types
2378
+ messageTypes: null, // Will store message types from __playground_message_types
2379
+ pingMs: null, // Current ping value in milliseconds
2380
+ pingInterval: null // Interval for pinging the room
2272
2381
  };
2273
2382
  roomDebugInfo.set(uniquePanelId, debugInfo);
2383
+ // Start ping interval (every 2 seconds)
2384
+ debugInfo.pingInterval = setInterval(() => {
2385
+ room.ping((ms) => {
2386
+ debugInfo.pingMs = ms;
2387
+ });
2388
+ }, 2000);
2389
+ // Initial ping
2390
+ room.ping((ms) => {
2391
+ debugInfo.pingMs = ms;
2392
+ });
2274
2393
  // Listen for __playground_message_types message
2275
2394
  room.onMessage('__playground_message_types', (messageTypes) => {
2276
2395
  debugInfo.messageTypes = messageTypes;
2277
- // Show/hide message icon based on message types availability
2278
- var messageIconElement = document.getElementById('debug-message-icon-' + uniquePanelId);
2279
- if (messageIconElement) {
2280
- messageIconElement.style.display = messageTypes ? 'inline-flex' : 'none';
2396
+ // Show/hide message button based on message types availability
2397
+ var messageBtnElement = document.getElementById('debug-message-btn-' + uniquePanelId);
2398
+ if (messageBtnElement) {
2399
+ messageBtnElement.style.display = messageTypes ? 'flex' : 'none';
2281
2400
  }
2282
2401
  });
2283
2402
  // Helper function to track received message/bytes
@@ -2325,41 +2444,38 @@ function applyMonkeyPatches() {
2325
2444
  debugInfo.bytesSent += data.length;
2326
2445
  debugInfo.bytesSentDelta += data.length;
2327
2446
  }
2328
- // Monkey-patch: WebSocket transport
2329
- if (transport.ws) {
2330
- const originalOnMessage = transport.ws.onmessage;
2331
- const ws = transport.ws;
2332
- transport.ws.onmessage = function (event) {
2333
- // Clone event data to avoid issues with delayed processing
2334
- var eventData = event.data;
2335
- if (eventData instanceof Blob) {
2336
- eventData = eventData.slice();
2337
- }
2338
- else if (eventData instanceof ArrayBuffer) {
2339
- eventData = eventData.slice(0);
2340
- }
2341
- else if (typeof eventData === 'string') {
2342
- eventData = eventData;
2343
- }
2344
- trackReceivedMessage(eventData);
2345
- // Apply latency simulation for received messages
2346
- if (preferences.latencySimulation.enabled && preferences.latencySimulation.delay > 0) {
2347
- setTimeout(function () {
2348
- // Create a synthetic event-like object
2349
- var syntheticEvent = {
2350
- data: eventData,
2351
- target: ws,
2352
- currentTarget: ws,
2353
- type: 'message'
2354
- };
2355
- originalOnMessage.call(ws, syntheticEvent);
2356
- }, preferences.latencySimulation.delay);
2357
- }
2358
- else {
2359
- return originalOnMessage.apply(this, arguments);
2360
- }
2361
- };
2362
- }
2447
+ // Monkey-patch: track received messages through onmessage event
2448
+ const originalOnMessage = transport.events.onmessage;
2449
+ transport.events.onmessage = function (event) {
2450
+ // Clone event data to avoid issues with delayed processing
2451
+ var eventData = event.data;
2452
+ if (eventData instanceof Blob) {
2453
+ eventData = eventData.slice();
2454
+ }
2455
+ else if (eventData instanceof ArrayBuffer) {
2456
+ eventData = eventData.slice(0);
2457
+ }
2458
+ else if (typeof eventData === 'string') {
2459
+ eventData = eventData;
2460
+ }
2461
+ trackReceivedMessage(eventData);
2462
+ // Apply latency simulation for received messages
2463
+ if (preferences.latencySimulation.enabled && preferences.latencySimulation.delay > 0) {
2464
+ setTimeout(function () {
2465
+ // Create a synthetic event-like object
2466
+ var syntheticEvent = {
2467
+ data: eventData,
2468
+ target: event.target,
2469
+ currentTarget: event.currentTarget,
2470
+ type: 'message'
2471
+ };
2472
+ originalOnMessage.call(event.target, syntheticEvent);
2473
+ }, preferences.latencySimulation.delay);
2474
+ }
2475
+ else {
2476
+ return originalOnMessage.apply(this, arguments);
2477
+ }
2478
+ };
2363
2479
  // Monkey-patch: sending messages through room connection
2364
2480
  const originalSend = room.connection.send.bind(room.connection);
2365
2481
  room.connection.send = function (data) {
@@ -2389,6 +2505,11 @@ function applyMonkeyPatches() {
2389
2505
  ensureGlobalUpdateInterval();
2390
2506
  // Clean up on room leave
2391
2507
  room.onLeave.once(() => {
2508
+ // Clear ping interval
2509
+ if (debugInfo.pingInterval !== null) {
2510
+ clearInterval(debugInfo.pingInterval);
2511
+ debugInfo.pingInterval = null;
2512
+ }
2392
2513
  roomDebugInfo.delete(uniquePanelId);
2393
2514
  var panel = document.getElementById('debug-panel-' + uniquePanelId);
2394
2515
  if (panel) {
@@ -2411,31 +2532,23 @@ function applyMonkeyPatches() {
2411
2532
  // Patch joinOrCreate
2412
2533
  Client.prototype.joinOrCreate = function () {
2413
2534
  var promise = originalJoinOrCreate.apply(this, arguments);
2414
- return promise.then(function (room) {
2415
- return patchRoom(room);
2416
- });
2535
+ return promise.then((room) => patchRoom(room));
2417
2536
  };
2418
2537
  // Patch join
2419
2538
  Client.prototype.join = function () {
2420
2539
  var promise = originalJoin.apply(this, arguments);
2421
- return promise.then(function (room) {
2422
- return patchRoom(room);
2423
- });
2540
+ return promise.then((room) => patchRoom(room));
2424
2541
  };
2425
2542
  // Patch create
2426
2543
  Client.prototype.create = function () {
2427
2544
  var promise = originalCreate.apply(this, arguments);
2428
- return promise.then(function (room) {
2429
- return patchRoom(room);
2430
- });
2545
+ return promise.then((room) => patchRoom(room));
2431
2546
  };
2432
2547
  // Patch reconnect
2433
2548
  if (originalReconnect) {
2434
2549
  Client.prototype.reconnect = function () {
2435
2550
  var promise = originalReconnect.apply(this, arguments);
2436
- return promise.then(function (room) {
2437
- return patchRoom(room);
2438
- });
2551
+ return promise.then((room) => patchRoom(room));
2439
2552
  };
2440
2553
  }
2441
2554
  }