Summary
Auto-reconnect uses a flat 10s retry with no backoff, no cap, and no respect for a server-initiated goodbye, so a kicked or banned client reconnects forever.
Details
src/client.ts:171-179:
this.ws.onclose = () => {
this.cleanupConnection();
if (!this.intentionalDisconnect) {
this.reconnectTimer = setTimeout(() => { this.connect(); }, 10000);
}
};
intentionalDisconnect is only ever set by close() (line 285), i.e. a local user action. A server that closes the socket to kick or ban the user gets reconnected to 10 seconds later, indefinitely. There is no exponential backoff, no jitter, and no maximum attempt count.
GMCPCore.handleGoodbye (src/gmcp/Core.ts) only logs, so a Core.Goodbye from the server does not suppress the reconnect.
Fix direction
Add capped exponential backoff with jitter, and have handleGoodbye set a flag that suppresses auto-reconnect.
Verification
Read src/client.ts end to end.
Summary
Auto-reconnect uses a flat 10s retry with no backoff, no cap, and no respect for a server-initiated goodbye, so a kicked or banned client reconnects forever.
Details
src/client.ts:171-179:intentionalDisconnectis only ever set byclose()(line 285), i.e. a local user action. A server that closes the socket to kick or ban the user gets reconnected to 10 seconds later, indefinitely. There is no exponential backoff, no jitter, and no maximum attempt count.GMCPCore.handleGoodbye(src/gmcp/Core.ts) only logs, so aCore.Goodbyefrom the server does not suppress the reconnect.Fix direction
Add capped exponential backoff with jitter, and have
handleGoodbyeset a flag that suppresses auto-reconnect.Verification
Read
src/client.tsend to end.