mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 08:20:14 +01:00
fix: attempt reconnection on token expiry
This commit is contained in:
parent
b68d16bdea
commit
7c38d6d1b0
2 changed files with 31 additions and 10 deletions
|
|
@ -250,23 +250,50 @@ describe('OAuthReconnectionManager', () => {
|
||||||
expect(mockMCPManager.disconnectUserConnection).toHaveBeenCalledWith(userId, 'server1');
|
expect(mockMCPManager.disconnectUserConnection).toHaveBeenCalledWith(userId, 'server1');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not reconnect servers with expired tokens', async () => {
|
it('should attempt to reconnect servers with expired tokens (refresh will be attempted)', async () => {
|
||||||
const userId = 'user-123';
|
const userId = 'user-123';
|
||||||
const oauthServers = new Set(['server1']);
|
const oauthServers = new Set(['server1']);
|
||||||
(mcpServersRegistry.getOAuthServers as jest.Mock).mockResolvedValue(oauthServers);
|
(mcpServersRegistry.getOAuthServers as jest.Mock).mockResolvedValue(oauthServers);
|
||||||
|
|
||||||
// server1: has expired token
|
// server1: has expired token (but refresh token should still work)
|
||||||
tokenMethods.findToken.mockResolvedValue({
|
tokenMethods.findToken.mockResolvedValue({
|
||||||
userId,
|
userId,
|
||||||
identifier: 'mcp:server1',
|
identifier: 'mcp:server1',
|
||||||
expiresAt: new Date(Date.now() - 3600000), // 1 hour ago
|
expiresAt: new Date(Date.now() - 3600000), // 1 hour ago
|
||||||
} as unknown as MCPOAuthTokens);
|
} as unknown as MCPOAuthTokens);
|
||||||
|
|
||||||
|
// Mock successful reconnection (token refresh happens internally)
|
||||||
|
const mockConnection = {
|
||||||
|
isConnected: jest.fn().mockResolvedValue(true),
|
||||||
|
};
|
||||||
|
mockMCPManager.getUserConnection.mockResolvedValue(
|
||||||
|
mockConnection as unknown as MCPConnection,
|
||||||
|
);
|
||||||
|
(mcpServersRegistry.getServerConfig as jest.Mock).mockResolvedValue(
|
||||||
|
{} as unknown as MCPOptions,
|
||||||
|
);
|
||||||
|
|
||||||
await reconnectionManager.reconnectServers(userId);
|
await reconnectionManager.reconnectServers(userId);
|
||||||
|
|
||||||
// Verify no reconnection attempt was made
|
// Verify reconnection attempt was made (token refresh will happen during getUserConnection)
|
||||||
|
expect(reconnectionTracker.isActive(userId, 'server1')).toBe(true);
|
||||||
|
|
||||||
|
// Wait for async tryReconnect to complete
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||||
|
|
||||||
|
expect(mockMCPManager.getUserConnection).toHaveBeenCalledWith({
|
||||||
|
serverName: 'server1',
|
||||||
|
user: { id: userId },
|
||||||
|
flowManager,
|
||||||
|
tokenMethods,
|
||||||
|
forceNew: false,
|
||||||
|
connectionTimeout: 10000, // DEFAULT_CONNECTION_TIMEOUT_MS
|
||||||
|
returnOnOAuth: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verify successful reconnection cleared the states
|
||||||
|
expect(reconnectionTracker.isFailed(userId, 'server1')).toBe(false);
|
||||||
expect(reconnectionTracker.isActive(userId, 'server1')).toBe(false);
|
expect(reconnectionTracker.isActive(userId, 'server1')).toBe(false);
|
||||||
expect(mockMCPManager.getUserConnection).not.toHaveBeenCalled();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should handle connection that returns but is not connected', async () => {
|
it('should handle connection that returns but is not connected', async () => {
|
||||||
|
|
|
||||||
|
|
@ -174,12 +174,6 @@ export class OAuthReconnectionManager {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the token has expired, don't attempt to reconnect
|
|
||||||
const now = new Date();
|
|
||||||
if (accessToken.expiresAt && accessToken.expiresAt < now) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// …otherwise, we're good to go with the reconnect attempt
|
// …otherwise, we're good to go with the reconnect attempt
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue