diff --git a/packages/ui/src/stores/useFileSearchStore.test.ts b/packages/ui/src/stores/useFileSearchStore.test.ts index 59fa60c1..ad59eaa8 100644 --- a/packages/ui/src/stores/useFileSearchStore.test.ts +++ b/packages/ui/src/stores/useFileSearchStore.test.ts @@ -89,4 +89,16 @@ describe('useFileSearchStore', () => { expect(cacheEntries).toHaveLength(1); expect(cacheEntries[0]?.files).toEqual([{ path: 'fresh.ts' }]); }); + + test('keeps directory and query separators from colliding in cache keys', async () => { + const firstPromise = useFileSearchStore.getState().searchFiles('/project::nested', 'foo'); + searchRequests[0].resolve([{ path: 'first.ts' }]); + await firstPromise; + + const secondPromise = useFileSearchStore.getState().searchFiles('/project', 'nested::foo'); + expect(searchRequests).toHaveLength(2); + + searchRequests[1].resolve([{ path: 'second.ts' }]); + expect(await secondPromise).toEqual([{ path: 'second.ts' }]); + }); }); diff --git a/packages/ui/src/stores/useFileSearchStore.ts b/packages/ui/src/stores/useFileSearchStore.ts index 65b01736..31e969b5 100644 --- a/packages/ui/src/stores/useFileSearchStore.ts +++ b/packages/ui/src/stores/useFileSearchStore.ts @@ -34,7 +34,16 @@ const buildCacheKey = ( ) => { const normalizedDirectory = directory.trim(); const normalizedQuery = query.trim().toLowerCase(); - return `${normalizedDirectory}::${normalizedQuery}::${limit}::${includeHidden ? '1' : '0'}::${respectGitignore ? '1' : '0'}::${type}`; + return JSON.stringify([normalizedDirectory, normalizedQuery, limit, includeHidden, respectGitignore, type]); +}; + +const cacheKeyMatchesDirectory = (cacheKey: string, directory: string) => { + try { + const value: unknown = JSON.parse(cacheKey); + return Array.isArray(value) && value[0] === directory; + } catch { + return false; + } }; export const useFileSearchStore = create()( @@ -127,12 +136,11 @@ export const useFileSearchStore = create()( } const normalizedDirectory = directory.trim(); - const prefix = `${normalizedDirectory}::`; set((state) => { const nextCache = { ...state.cache }; const nextKeys = state.cacheKeys.filter((cacheKey) => { - if (cacheKey.startsWith(prefix)) { + if (cacheKeyMatchesDirectory(cacheKey, normalizedDirectory)) { delete nextCache[cacheKey]; return false; } @@ -140,7 +148,7 @@ export const useFileSearchStore = create()( }); const nextInFlightEntries = Object.entries(state.inFlight).filter( - ([key]) => !key.startsWith(prefix) + ([key]) => !cacheKeyMatchesDirectory(key, normalizedDirectory) ); const nextInFlight = Object.fromEntries(nextInFlightEntries);