11'use client' ;
22
3- import { RepositoryInfo , SearchRequest , SearchResponse , SearchResultFile } from '@/features/search/types' ;
3+ import { RepositoryInfo , SearchRequest , SearchResultFile , SearchStats , StreamedSearchResponse } from '@/features/search/types' ;
44import { useState , useCallback , useRef , useEffect } from 'react' ;
55import * as Sentry from '@sentry/nextjs' ;
66
@@ -10,6 +10,7 @@ interface CacheEntry {
1010 numMatches : number ;
1111 durationMs : number ;
1212 timestamp : number ;
13+ isExhaustive : boolean ;
1314}
1415
1516const searchCache = new Map < string , CacheEntry > ( ) ;
@@ -34,18 +35,22 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
3435
3536 const [ state , setState ] = useState < {
3637 isStreaming : boolean ,
38+ isExhaustive : boolean ,
3739 error : Error | null ,
3840 files : SearchResultFile [ ] ,
3941 repoInfo : Record < number , RepositoryInfo > ,
4042 durationMs : number ,
4143 numMatches : number ,
44+ stats ?: SearchStats ,
4245 } > ( {
4346 isStreaming : false ,
47+ isExhaustive : false ,
4448 error : null ,
4549 files : [ ] ,
4650 repoInfo : { } ,
4751 durationMs : 0 ,
4852 numMatches : 0 ,
53+ stats : undefined ,
4954 } ) ;
5055
5156 const abortControllerRef = useRef < AbortController | null > ( null ) ;
@@ -85,6 +90,7 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
8590 console . debug ( 'Using cached search results' ) ;
8691 setState ( {
8792 isStreaming : false ,
93+ isExhaustive : cachedEntry . isExhaustive ,
8894 error : null ,
8995 files : cachedEntry . files ,
9096 repoInfo : cachedEntry . repoInfo ,
@@ -96,6 +102,7 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
96102
97103 setState ( {
98104 isStreaming : true ,
105+ isExhaustive : false ,
99106 error : null ,
100107 files : [ ] ,
101108 repoInfo : { } ,
@@ -167,22 +174,33 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
167174 break ;
168175 }
169176
170- const chunk : SearchResponse = JSON . parse ( data ) ;
171- setState ( prev => ( {
172- ...prev ,
173- files : [
174- ...prev . files ,
175- ...chunk . files
176- ] ,
177- repoInfo : {
178- ...prev . repoInfo ,
179- ...chunk . repositoryInfo . reduce ( ( acc , repo ) => {
180- acc [ repo . id ] = repo ;
181- return acc ;
182- } , { } as Record < number , RepositoryInfo > ) ,
183- } ,
184- numMatches : prev . numMatches + chunk . stats . actualMatchCount ,
185- } ) ) ;
177+ const response : StreamedSearchResponse = JSON . parse ( data ) ;
178+ switch ( response . type ) {
179+ case 'chunk' :
180+ setState ( prev => ( {
181+ ...prev ,
182+ files : [
183+ ...prev . files ,
184+ ...response . files
185+ ] ,
186+ repoInfo : {
187+ ...prev . repoInfo ,
188+ ...response . repositoryInfo . reduce ( ( acc , repo ) => {
189+ acc [ repo . id ] = repo ;
190+ return acc ;
191+ } , { } as Record < number , RepositoryInfo > ) ,
192+ } ,
193+ numMatches : prev . numMatches + response . stats . actualMatchCount ,
194+ } ) ) ;
195+ break ;
196+ case 'final' :
197+ setState ( prev => ( {
198+ ...prev ,
199+ isExhaustive : response . isSearchExhaustive ,
200+ stats : response . accumulatedStats ,
201+ } ) ) ;
202+ break ;
203+ }
186204 }
187205 }
188206
@@ -192,6 +210,7 @@ export const useStreamedSearch = ({ query, matches, contextLines, whole, isRegex
192210 searchCache . set ( cacheKey , {
193211 files : prev . files ,
194212 repoInfo : prev . repoInfo ,
213+ isExhaustive : prev . isExhaustive ,
195214 numMatches : prev . numMatches ,
196215 durationMs,
197216 timestamp : Date . now ( ) ,
0 commit comments