fix(extensions): tighten plugin catalog fallback state
This commit is contained in:
parent
afad52f506
commit
09b5b4626f
2 changed files with 36 additions and 3 deletions
|
|
@ -237,15 +237,19 @@ export const createExtensionsSlice: StateCreator<AppState, [], [], ExtensionsSli
|
|||
};
|
||||
});
|
||||
} catch (err) {
|
||||
set(() => {
|
||||
set((prev) => {
|
||||
if (requestSeq !== pluginCatalogRequestSeq) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const nextProjectPath = projectPath ?? null;
|
||||
const isSameProjectContext = prev.pluginCatalogProjectPath === nextProjectPath;
|
||||
|
||||
return {
|
||||
pluginCatalog: isSameProjectContext ? prev.pluginCatalog : [],
|
||||
pluginCatalogLoading: false,
|
||||
pluginCatalogError: err instanceof Error ? err.message : 'Failed to load plugins',
|
||||
pluginCatalogProjectPath: projectPath ?? null,
|
||||
pluginCatalogProjectPath: nextProjectPath,
|
||||
};
|
||||
});
|
||||
} finally {
|
||||
|
|
@ -263,7 +267,13 @@ export const createExtensionsSlice: StateCreator<AppState, [], [], ExtensionsSli
|
|||
fetchPluginReadme: (pluginId: string) => {
|
||||
if (!api.plugins) return;
|
||||
const state = get();
|
||||
if (pluginId in state.pluginReadmes || state.pluginReadmeLoading[pluginId]) return;
|
||||
const cachedReadme = state.pluginReadmes[pluginId];
|
||||
if (
|
||||
(cachedReadme !== undefined && cachedReadme !== null) ||
|
||||
state.pluginReadmeLoading[pluginId]
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
set((prev) => ({
|
||||
pluginReadmeLoading: { ...prev.pluginReadmeLoading, [pluginId]: true },
|
||||
|
|
|
|||
|
|
@ -167,6 +167,20 @@ describe('extensionsSlice', () => {
|
|||
expect(store.getState().pluginCatalogLoading).toBe(false);
|
||||
});
|
||||
|
||||
it('clears stale catalog when a different project fetch fails', async () => {
|
||||
store.setState({
|
||||
pluginCatalog: [makePlugin({ pluginId: 'project-a@m' })],
|
||||
pluginCatalogProjectPath: '/tmp/project-a',
|
||||
});
|
||||
(api.plugins!.getAll as ReturnType<typeof vi.fn>).mockRejectedValue(new Error('boom'));
|
||||
|
||||
await store.getState().fetchPluginCatalog('/tmp/project-b');
|
||||
|
||||
expect(store.getState().pluginCatalog).toEqual([]);
|
||||
expect(store.getState().pluginCatalogProjectPath).toBe('/tmp/project-b');
|
||||
expect(store.getState().pluginCatalogError).toBe('boom');
|
||||
});
|
||||
|
||||
it('dedups concurrent requests for the same project key', async () => {
|
||||
let resolveFetch!: (plugins: EnrichedPlugin[]) => void;
|
||||
const inFlight = new Promise<EnrichedPlugin[]>((resolve) => {
|
||||
|
|
@ -243,6 +257,15 @@ describe('extensionsSlice', () => {
|
|||
|
||||
expect(api.plugins!.getReadme).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('retries README fetch when the cached value is null', () => {
|
||||
store.setState({ pluginReadmes: { 'test@m': null } });
|
||||
(api.plugins!.getReadme as ReturnType<typeof vi.fn>).mockResolvedValue(null);
|
||||
|
||||
store.getState().fetchPluginReadme('test@m');
|
||||
|
||||
expect(api.plugins!.getReadme).toHaveBeenCalledWith('test@m');
|
||||
});
|
||||
});
|
||||
|
||||
describe('mcpBrowse', () => {
|
||||
|
|
|
|||
Loading…
Reference in a new issue