feat: wire rule registry and client-authenticated callback into server runtime
- Add ruleRegistry and onClientAuthenticated options to YonexusServerRuntime - Dispatch rewritten rule messages (rule::sender::content) to rule registry - Guard onClientAuthenticated behind promoteToAuthenticated return value - Fix transport message handler: use tempConn directly when ws is in temp state, preventing stale _connections entry from causing promoteToAuthenticated to fail - Close competing temp connections with same identifier on promotion - Expose __yonexusServer on globalThis for cross-plugin communication - Remove auto-failure on admin notification miss; pairing stays pending Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -186,6 +186,16 @@ export class YonexusServerTransport implements ServerTransport {
|
||||
this._connections.delete(identifier);
|
||||
}
|
||||
|
||||
// Also close any OTHER temp connections that claimed the same identifier.
|
||||
// This handles the case where a second hello came in with the same identifier
|
||||
// while the first was still in the temp/pairing phase.
|
||||
for (const [otherWs, otherTemp] of this.tempConnections.entries()) {
|
||||
if (otherWs !== ws && otherTemp.assignedIdentifier === identifier) {
|
||||
otherWs.close(1008, "Connection replaced by new authenticated session");
|
||||
this.tempConnections.delete(otherWs);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from temp connections
|
||||
this.tempConnections.delete(ws);
|
||||
|
||||
@@ -229,22 +239,24 @@ export class YonexusServerTransport implements ServerTransport {
|
||||
|
||||
ws.on("message", (data: RawData) => {
|
||||
const message = data.toString("utf8");
|
||||
// Try to get identifier from temp connections first, then authenticated connections
|
||||
let identifier: string | null = null;
|
||||
const tempData = this.tempConnections.get(ws);
|
||||
if (tempData) {
|
||||
identifier = tempData.assignedIdentifier;
|
||||
}
|
||||
if (!identifier) {
|
||||
for (const [id, conn] of this._connections) {
|
||||
if (conn.ws === ws) {
|
||||
identifier = id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If this ws is still in temp state, use tempConn directly.
|
||||
// Never fall through to _connections — it may hold a stale entry for the
|
||||
// same identifier from a previously-authenticated session that hasn't
|
||||
// finished closing yet, which would cause promoteToAuthenticated to receive
|
||||
// the wrong WebSocket and silently fail.
|
||||
if (this.tempConnections.has(ws)) {
|
||||
this.options.onMessage(tempConn, message);
|
||||
return;
|
||||
}
|
||||
|
||||
const connection = identifier ? this._connections.get(identifier) ?? tempConn : tempConn;
|
||||
// ws has been promoted — find it in authenticated connections
|
||||
let connection: ClientConnection = tempConn;
|
||||
for (const [, conn] of this._connections) {
|
||||
if (conn.ws === ws) {
|
||||
connection = conn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.options.onMessage(connection, message);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user