🔑 fix: Auth-Aware Startup Config Caching for Fresh Sessions (#12505)

* fix: auth-aware config caching for fresh sessions

- Add auth state to startup config query key via shared `startupConfigKey`
  builder so login (unauthenticated) and chat (authenticated) configs are
  cached independently
- Disable queries during login onMutate to prevent premature unauthenticated
  refetches after cache clear
- Re-enable queries in setUserContext only after setTokenHeader runs, with
  positive-only guard to avoid redundant disable on logout
- Update all getQueryData call sites to use the shared key builder
- Fall back to getConfigDefaults().interface in useEndpoints, hoisted to
  module-level constant to avoid per-render recomputation

* fix: address review findings for auth-aware config caching

- Move defaultInterface const after all imports in ModelSelector.tsx
- Remove dead QueryKeys import, use import type for TStartupConfig
  in ImportConversations.tsx
- Spread real exports in useQueryParams.spec.ts mock to preserve
  startupConfigKey, fixing TypeError in all 6 tests

* chore: import order

* fix: re-enable queries on login failure

When login fails, onSuccess never fires so queriesEnabled stays
false. Re-enable in onError so the login page can re-fetch config
(needed for LDAP username validation and social login options).
This commit is contained in:
Danny Avila 2026-04-01 17:20:39 -04:00 committed by GitHub
parent c4b5dedb77
commit 7b368916d5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 59 additions and 30 deletions

View file

@ -15,6 +15,8 @@ import { CustomMenu as Menu } from './CustomMenu';
import DialogManager from './DialogManager';
import { useLocalize } from '~/hooks';
const defaultInterface = getConfigDefaults().interface;
function ModelSelectorContent() {
const localize = useLocalize();
@ -122,7 +124,7 @@ function ModelSelectorContent() {
}
export default function ModelSelector({ startupConfig }: ModelSelectorProps) {
const interfaceConfig = startupConfig?.interface ?? getConfigDefaults().interface;
const interfaceConfig = startupConfig?.interface ?? defaultInterface;
const modelSpecs = startupConfig?.modelSpecs?.list ?? [];
// Hide the selector when modelSelect is false and there are no model specs to show

View file

@ -1,9 +1,9 @@
import { useState, useRef, useCallback } from 'react';
import { Import } from 'lucide-react';
import { useQueryClient } from '@tanstack/react-query';
import { QueryKeys, TStartupConfig } from 'librechat-data-provider';
import type { TStartupConfig } from 'librechat-data-provider';
import { Spinner, useToastContext, Label, Button } from '@librechat/client';
import { useUploadConversationsMutation } from '~/data-provider';
import { startupConfigKey, useUploadConversationsMutation } from '~/data-provider';
import { NotificationSeverity } from '~/common';
import { useLocalize } from '~/hooks';
import { cn, logger } from '~/utils';
@ -51,7 +51,7 @@ function ImportConversations() {
const handleFileUpload = useCallback(
async (file: File) => {
try {
const startupConfig = queryClient.getQueryData<TStartupConfig>([QueryKeys.startupConfig]);
const startupConfig = queryClient.getQueryData<TStartupConfig>(startupConfigKey(true));
const maxFileSize = startupConfig?.conversationImportMaxFileSize;
if (maxFileSize && file.size > maxFileSize) {
const size = (maxFileSize / (1024 * 1024)).toFixed(2);