563bb99
import type { ReactNode } from 'react'
import { alovaInstance } from '@/shared/api'
import { ThemeProvider } from '@/shared/ui'
import { VoiceHost } from '@/shared/voice'
import { installVoiceSession } from '@/features/chat'
import { ApiErrorGate } from './api-error-gate'
/**
* App-wide providers (Redux / QueryClient / theme / auth context, ...).
*
* Alova is provider-less, so the only wiring here is instance configuration.
* Keeping provider composition here lets `app/index.tsx` stay pure bootstrap.
*/
/**
* Alova caches GET responses in memory for 5 minutes by default and this app
* has no cache-invalidation layer (useAsync refetches on mount/route change).
* Without this, a mutation such as creating a space keeps rendering the list
* cached before the POST, so the new row never appears until a tab reload.
* Disabling GET response caching fixes every list; concurrent identical
* requests are still deduplicated by shareRequest.
*/
alovaInstance.options.cacheFor = { GET: 0 }
/**
* Voice needs two app-level hooks because the call outlives every route:
* the session gets its credential source (and its refresh restore) from the
* chat feature, and `VoiceHost` feeds the same Room to the vendored LiveKit
* components so remote audio and the connection toast keep working while the
* user browses a repository or a board.
*/
installVoiceSession()
export function AppProviders({ children }: { children: ReactNode }) {
// The outage gate is deliberately above the router: it is a property of the
// transport, not of any single route, and it must be able to swallow the
// whole tree (auth screens included) without touching the URL.
return (
<ApiErrorGate>
<ThemeProvider>
<VoiceHost />
{children}
</ThemeProvider>
</ApiErrorGate>
)
}